diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2012-03-15 11:08:55 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2012-03-15 11:08:55 -0400 |
commit | b7a6f90d3700011af95712bbd6f8ec4aa89a63e9 (patch) | |
tree | 33af07c0c60829e04e0eebb61a380bfc9a5c74fd | |
parent | Grsec/PaX: 2.9-2.6.32.58-201203062047 + 2.9-3.2.9-201203062051 (diff) | |
download | hardened-patchset-20120314.tar.gz hardened-patchset-20120314.tar.bz2 hardened-patchset-20120314.zip |
Grsec/PaX: 2.9-2.6.32.58-201203131839 + 2.9-3.2.11-20120314195620120314
-rw-r--r-- | 2.6.32/0000_README | 2 | ||||
-rw-r--r-- | 2.6.32/4420_grsecurity-2.9-2.6.32.58-201203131839.patch (renamed from 2.6.32/4420_grsecurity-2.9-2.6.32.58-201203062047.patch) | 18315 | ||||
-rw-r--r-- | 2.6.32/4445_grsec-pax-without-grsec.patch | 11 | ||||
-rw-r--r-- | 2.6.32/4450_grsec-kconfig-default-gids.patch | 14 | ||||
-rw-r--r-- | 2.6.32/4460-grsec-kconfig-proc-user.patch | 4 | ||||
-rw-r--r-- | 2.6.32/4465_selinux-avc_audit-log-curr_ip.patch | 2 | ||||
-rw-r--r-- | 3.2.11/0000_README (renamed from 3.2.9/0000_README) | 2 | ||||
-rw-r--r-- | 3.2.11/4420_grsecurity-2.9-3.2.11-201203141956.patch (renamed from 3.2.9/4420_grsecurity-2.9-3.2.9-201203062051.patch) | 2007 | ||||
-rw-r--r-- | 3.2.11/4425_grsec_enable_xtpax.patch (renamed from 3.2.9/4425_grsec_enable_xtpax.patch) | 0 | ||||
-rw-r--r-- | 3.2.11/4430_grsec-remove-localversion-grsec.patch (renamed from 3.2.9/4430_grsec-remove-localversion-grsec.patch) | 0 | ||||
-rw-r--r-- | 3.2.11/4435_grsec-mute-warnings.patch (renamed from 3.2.9/4435_grsec-mute-warnings.patch) | 0 | ||||
-rw-r--r-- | 3.2.11/4440_grsec-remove-protected-paths.patch (renamed from 3.2.9/4440_grsec-remove-protected-paths.patch) | 2 | ||||
-rw-r--r-- | 3.2.11/4445_grsec-pax-without-grsec.patch (renamed from 3.2.9/4445_grsec-pax-without-grsec.patch) | 11 | ||||
-rw-r--r-- | 3.2.11/4450_grsec-kconfig-default-gids.patch (renamed from 3.2.9/4450_grsec-kconfig-default-gids.patch) | 14 | ||||
-rw-r--r-- | 3.2.11/4455_grsec-kconfig-gentoo.patch (renamed from 3.2.9/4455_grsec-kconfig-gentoo.patch) | 0 | ||||
-rw-r--r-- | 3.2.11/4460-grsec-kconfig-proc-user.patch (renamed from 3.2.9/4460-grsec-kconfig-proc-user.patch) | 4 | ||||
-rw-r--r-- | 3.2.11/4465_selinux-avc_audit-log-curr_ip.patch (renamed from 3.2.9/4465_selinux-avc_audit-log-curr_ip.patch) | 2 | ||||
-rw-r--r-- | 3.2.11/4470_disable-compat_vdso.patch (renamed from 3.2.9/4470_disable-compat_vdso.patch) | 0 |
18 files changed, 20018 insertions, 372 deletions
diff --git a/2.6.32/0000_README b/2.6.32/0000_README index c4a9001..1858adf 100644 --- a/2.6.32/0000_README +++ b/2.6.32/0000_README @@ -22,7 +22,7 @@ Patch: 1056_linux-2.6.32.57.patch From: http://www.kernel.org Desc: Linux 2.6.32.57 -Patch: 4420_grsecurity-2.9-2.6.32.58-201203062047.patch +Patch: 4420_grsecurity-2.9-2.6.32.58-201203131839.patch From: http://www.grsecurity.net Desc: hardened-sources base patch from upstream grsecurity diff --git a/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203062047.patch b/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203131839.patch index bbdf047..325d13c 100644 --- a/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203062047.patch +++ b/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203131839.patch @@ -1,5 +1,5 @@ diff --git a/Documentation/dontdiff b/Documentation/dontdiff -index e1efc40..47f0daf 100644 +index e1efc40..76e689e 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -1,15 +1,19 @@ @@ -96,7 +96,15 @@ index e1efc40..47f0daf 100644 keywords.c ksym.c* ksym.h* -@@ -127,13 +148,16 @@ machtypes.h +@@ -117,6 +138,7 @@ kxgettext + lkc_defs.h + lex.c + lex.*.c ++lib1funcs.S + logo_*.c + logo_*_clut224.c + logo_*_mono.c +@@ -127,13 +149,16 @@ machtypes.h map maui_boot.h mconf @@ -113,7 +121,7 @@ index e1efc40..47f0daf 100644 mktables mktree modpost -@@ -149,6 +173,7 @@ patches* +@@ -149,6 +174,7 @@ patches* pca200e.bin pca200e_ecd.bin2 piggy.gz @@ -121,7 +129,7 @@ index e1efc40..47f0daf 100644 piggyback pnmtologo ppc_defs.h* -@@ -157,12 +182,15 @@ qconf +@@ -157,12 +183,15 @@ qconf raid6altivec*.c raid6int*.c raid6tables.c @@ -137,7 +145,7 @@ index e1efc40..47f0daf 100644 sm_tbl* split-include syscalltab.h -@@ -171,6 +199,7 @@ tftpboot.img +@@ -171,6 +200,7 @@ tftpboot.img timeconst.h times.h* trix_boot.h @@ -145,7 +153,7 @@ index e1efc40..47f0daf 100644 utsrelease.h* vdso-syms.lds vdso.lds -@@ -186,14 +215,20 @@ version.h* +@@ -186,14 +216,20 @@ version.h* vmlinux vmlinux-* vmlinux.aout @@ -184,8 +192,27 @@ index c840e7d..f4c451c 100644 pcbit= [HW,ISDN] pcd. [PARIDE] +diff --git a/MAINTAINERS b/MAINTAINERS +index 613da5d..4fe3eda 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -5725,6 +5725,14 @@ L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/vmxnet3/ + ++VMware PVSCSI driver ++M: Alok Kataria <akataria@vmware.com> ++M: VMware PV-Drivers <pv-drivers@vmware.com> ++L: linux-scsi@vger.kernel.org ++S: Maintained ++F: drivers/scsi/vmw_pvscsi.c ++F: drivers/scsi/vmw_pvscsi.h ++ + VOLTAGE AND CURRENT REGULATOR FRAMEWORK + M: Liam Girdwood <lrg@slimlogic.co.uk> + M: Mark Brown <broonie@opensource.wolfsonmicro.com> diff --git a/Makefile b/Makefile -index ed78982..bcc432e 100644 +index ed78982..cb8fa66 100644 --- a/Makefile +++ b/Makefile @@ -221,8 +221,9 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ @@ -220,7 +247,7 @@ index ed78982..bcc432e 100644 include/linux/version.h headers_% \ kernelrelease kernelversion -@@ -526,6 +527,48 @@ else +@@ -526,6 +527,50 @@ else KBUILD_CFLAGS += -O2 endif @@ -246,7 +273,9 @@ index ed78982..bcc432e 100644 +CHECKER_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/checker_plugin.so -DCHECKER_PLUGIN +endif +endif -+GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS) $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS) ++COLORIZE_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/colorize_plugin.so ++GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS) ++GCC_PLUGINS_CFLAGS += $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS) $(COLORIZE_PLUGIN_CFLAGS) +GCC_PLUGINS_AFLAGS := $(KERNEXEC_PLUGIN_AFLAGS) +export CONSTIFY_PLUGIN STACKLEAK_PLUGIN KERNEXEC_PLUGIN CHECKER_PLUGIN +ifeq ($(KBUILD_EXTMOD),) @@ -269,7 +298,7 @@ index ed78982..bcc432e 100644 include $(srctree)/arch/$(SRCARCH)/Makefile ifneq ($(CONFIG_FRAME_WARN),0) -@@ -647,7 +690,7 @@ export mod_strip_cmd +@@ -647,7 +692,7 @@ export mod_strip_cmd ifeq ($(KBUILD_EXTMOD),) @@ -278,7 +307,7 @@ index ed78982..bcc432e 100644 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ -@@ -868,6 +911,8 @@ vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE +@@ -868,6 +913,8 @@ vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE # The actual objects are generated when descending, # make sure no implicit rule kicks in @@ -287,7 +316,7 @@ index ed78982..bcc432e 100644 $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; # Handle descending into subdirectories listed in $(vmlinux-dirs) -@@ -877,7 +922,7 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; +@@ -877,7 +924,7 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; # Error messages still appears in the original language PHONY += $(vmlinux-dirs) @@ -296,7 +325,7 @@ index ed78982..bcc432e 100644 $(Q)$(MAKE) $(build)=$@ # Build the kernel release string -@@ -986,6 +1031,7 @@ prepare0: archprepare FORCE +@@ -986,6 +1033,7 @@ prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. missing-syscalls # All the preparing.. @@ -304,7 +333,7 @@ index ed78982..bcc432e 100644 prepare: prepare0 # The asm symlink changes when $(ARCH) changes. -@@ -1127,6 +1173,8 @@ all: modules +@@ -1127,6 +1175,8 @@ all: modules # using awk while concatenating to the final file. PHONY += modules @@ -313,7 +342,7 @@ index ed78982..bcc432e 100644 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order @$(kecho) ' Building modules, stage 2.'; -@@ -1136,7 +1184,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) +@@ -1136,7 +1186,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) # Target to prepare building external modules PHONY += modules_prepare @@ -322,7 +351,7 @@ index ed78982..bcc432e 100644 # Target to install modules PHONY += modules_install -@@ -1201,7 +1249,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \ +@@ -1201,7 +1251,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \ include/linux/autoconf.h include/linux/version.h \ include/linux/utsrelease.h \ include/linux/bounds.h include/asm*/asm-offsets.h \ @@ -331,7 +360,7 @@ index ed78982..bcc432e 100644 # clean - Delete most, but leave enough to build external modules # -@@ -1245,7 +1293,7 @@ distclean: mrproper +@@ -1245,7 +1295,7 @@ distclean: mrproper @find $(srctree) $(RCS_FIND_IGNORE) \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ @@ -340,7 +369,7 @@ index ed78982..bcc432e 100644 -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ -type f -print | xargs rm -f -@@ -1292,6 +1340,7 @@ help: +@@ -1292,6 +1342,7 @@ help: @echo ' modules_prepare - Set up for building external modules' @echo ' tags/TAGS - Generate tags file for editors' @echo ' cscope - Generate cscope index' @@ -348,7 +377,7 @@ index ed78982..bcc432e 100644 @echo ' kernelrelease - Output the release version string' @echo ' kernelversion - Output the version stored in Makefile' @echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \ -@@ -1393,6 +1442,8 @@ PHONY += $(module-dirs) modules +@@ -1393,6 +1444,8 @@ PHONY += $(module-dirs) modules $(module-dirs): crmodverdir $(objtree)/Module.symvers $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) @@ -357,7 +386,7 @@ index ed78982..bcc432e 100644 modules: $(module-dirs) @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost -@@ -1448,7 +1499,7 @@ endif # KBUILD_EXTMOD +@@ -1448,7 +1501,7 @@ endif # KBUILD_EXTMOD quiet_cmd_tags = GEN $@ cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@ @@ -366,7 +395,7 @@ index ed78982..bcc432e 100644 $(call cmd,tags) # Scripts to check various things for consistency -@@ -1513,17 +1564,21 @@ else +@@ -1513,17 +1566,21 @@ else target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) endif @@ -392,7 +421,7 @@ index ed78982..bcc432e 100644 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) %.symtypes: %.c prepare scripts FORCE $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -@@ -1533,11 +1588,15 @@ endif +@@ -1533,11 +1590,15 @@ endif $(cmd_crmodverdir) $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ $(build)=$(build-dir) @@ -431,6 +460,33 @@ index 610dff4..f396854 100644 #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() #define smp_mb__before_atomic_inc() smp_mb() +diff --git a/arch/alpha/include/asm/cache.h b/arch/alpha/include/asm/cache.h +index f199e69..af005f5 100644 +--- a/arch/alpha/include/asm/cache.h ++++ b/arch/alpha/include/asm/cache.h +@@ -4,19 +4,20 @@ + #ifndef __ARCH_ALPHA_CACHE_H + #define __ARCH_ALPHA_CACHE_H + ++#include <linux/const.h> + + /* Bytes per L1 (data) cache line. */ + #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6) +-# define L1_CACHE_BYTES 64 + # define L1_CACHE_SHIFT 6 + #else + /* Both EV4 and EV5 are write-through, read-allocate, + direct-mapped, physical. + */ +-# define L1_CACHE_BYTES 32 + # define L1_CACHE_SHIFT 5 + #endif + ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) ++ + #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) + #define SMP_CACHE_BYTES L1_CACHE_BYTES + diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h index 5c75c1b..c82f878 100644 --- a/arch/alpha/include/asm/elf.h @@ -692,7 +748,7 @@ index b68faef..6dd1496 100644 select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h -index d0daeab..ff286a8 100644 +index d0daeab..ca7e10e 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -15,6 +15,10 @@ @@ -706,6 +762,271 @@ index d0daeab..ff286a8 100644 #define ATOMIC_INIT(i) { (i) } #ifdef __KERNEL__ +@@ -24,8 +28,16 @@ + * strex/ldrex monitor on some implementations. The reason we can use it for + * atomic_set() is the clrex or dummy strex done on every exception return. + */ +-#define atomic_read(v) ((v)->counter) ++#define atomic_read(v) (*(volatile int *)&(v)->counter) ++static inline int atomic_read_unchecked(const atomic_unchecked_t *v) ++{ ++ return v->counter; ++} + #define atomic_set(v,i) (((v)->counter) = (i)) ++static inline void atomic_set_unchecked(atomic_unchecked_t *v, int i) ++{ ++ v->counter = i; ++} + + #if __LINUX_ARM_ARCH__ >= 6 + +@@ -40,6 +52,35 @@ static inline void atomic_add(int i, atomic_t *v) + int result; + + __asm__ __volatile__("@ atomic_add\n" ++"1: ldrex %1, [%2]\n" ++" add %0, %1, %3\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strex %1, %0, [%2]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp) ++ : "r" (&v->counter), "Ir" (i) ++ : "cc"); ++} ++ ++static inline void atomic_add_unchecked(int i, atomic_unchecked_t *v) ++{ ++ unsigned long tmp; ++ int result; ++ ++ __asm__ __volatile__("@ atomic_add_unchecked\n" + "1: ldrex %0, [%2]\n" + " add %0, %0, %3\n" + " strex %1, %0, [%2]\n" +@@ -58,6 +99,42 @@ static inline int atomic_add_return(int i, atomic_t *v) + smp_mb(); + + __asm__ __volatile__("@ atomic_add_return\n" ++"1: ldrex %1, [%2]\n" ++" add %0, %1, %3\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strex %1, %0, [%2]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp) ++ : "r" (&v->counter), "Ir" (i) ++ : "cc"); ++ ++ smp_mb(); ++ ++ return result; ++} ++ ++static inline int atomic_add_return_unchecked(int i, atomic_unchecked_t *v) ++{ ++ unsigned long tmp; ++ int result; ++ ++ smp_mb(); ++ ++ __asm__ __volatile__("@ atomic_add_return_unchecked\n" + "1: ldrex %0, [%2]\n" + " add %0, %0, %3\n" + " strex %1, %0, [%2]\n" +@@ -78,6 +155,35 @@ static inline void atomic_sub(int i, atomic_t *v) + int result; + + __asm__ __volatile__("@ atomic_sub\n" ++"1: ldrex %1, [%2]\n" ++" sub %0, %1, %3\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strex %1, %0, [%2]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp) ++ : "r" (&v->counter), "Ir" (i) ++ : "cc"); ++} ++ ++static inline void atomic_sub_unchecked(int i, atomic_unchecked_t *v) ++{ ++ unsigned long tmp; ++ int result; ++ ++ __asm__ __volatile__("@ atomic_sub_unchecked\n" + "1: ldrex %0, [%2]\n" + " sub %0, %0, %3\n" + " strex %1, %0, [%2]\n" +@@ -96,11 +202,25 @@ static inline int atomic_sub_return(int i, atomic_t *v) + smp_mb(); + + __asm__ __volatile__("@ atomic_sub_return\n" +-"1: ldrex %0, [%2]\n" +-" sub %0, %0, %3\n" ++"1: ldrex %1, [%2]\n" ++" sub %0, %1, %3\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ + " strex %1, %0, [%2]\n" + " teq %1, #0\n" + " bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ + : "=&r" (result), "=&r" (tmp) + : "r" (&v->counter), "Ir" (i) + : "cc"); +@@ -132,6 +252,28 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) + return oldval; + } + ++static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *ptr, int old, int new) ++{ ++ unsigned long oldval, res; ++ ++ smp_mb(); ++ ++ do { ++ __asm__ __volatile__("@ atomic_cmpxchg_unchecked\n" ++ "ldrex %1, [%2]\n" ++ "mov %0, #0\n" ++ "teq %1, %3\n" ++ "strexeq %0, %4, [%2]\n" ++ : "=&r" (res), "=&r" (oldval) ++ : "r" (&ptr->counter), "Ir" (old), "r" (new) ++ : "cc"); ++ } while (res); ++ ++ smp_mb(); ++ ++ return oldval; ++} ++ + static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) + { + unsigned long tmp, tmp2; +@@ -207,6 +349,10 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) + #endif /* __LINUX_ARM_ARCH__ */ + + #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) ++{ ++ return xchg(&v->counter, new); ++} + + static inline int atomic_add_unless(atomic_t *v, int a, int u) + { +@@ -220,11 +366,27 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) + #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + + #define atomic_inc(v) atomic_add(1, v) ++static inline void atomic_inc_unchecked(atomic_unchecked_t *v) ++{ ++ atomic_add_unchecked(1, v); ++} + #define atomic_dec(v) atomic_sub(1, v) ++static inline void atomic_dec_unchecked(atomic_unchecked_t *v) ++{ ++ atomic_sub_unchecked(1, v); ++} + + #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) ++static inline int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) ++{ ++ return atomic_add_return_unchecked(1, v) == 0; ++} + #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) + #define atomic_inc_return(v) (atomic_add_return(1, v)) ++static inline int atomic_inc_return_unchecked(atomic_unchecked_t *v) ++{ ++ return atomic_add_return_unchecked(1, v); ++} + #define atomic_dec_return(v) (atomic_sub_return(1, v)) + #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) + +diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h +index 66c160b..bca1449 100644 +--- a/arch/arm/include/asm/cache.h ++++ b/arch/arm/include/asm/cache.h +@@ -4,8 +4,10 @@ + #ifndef __ASMARM_CACHE_H + #define __ASMARM_CACHE_H + ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT CONFIG_ARM_L1_CACHE_SHIFT +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + /* + * Memory returned by kmalloc() may be used for DMA, so we must make +diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h +index 3d0cdd2..19957c5 100644 +--- a/arch/arm/include/asm/cacheflush.h ++++ b/arch/arm/include/asm/cacheflush.h +@@ -216,13 +216,13 @@ struct cpu_cache_fns { + void (*dma_inv_range)(const void *, const void *); + void (*dma_clean_range)(const void *, const void *); + void (*dma_flush_range)(const void *, const void *); +-}; ++} __no_const; + + struct outer_cache_fns { + void (*inv_range)(unsigned long, unsigned long); + void (*clean_range)(unsigned long, unsigned long); + void (*flush_range)(unsigned long, unsigned long); +-}; ++} __no_const; + + /* + * Select the calling method diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 6aac3f5..265536b 100644 --- a/arch/arm/include/asm/elf.h @@ -738,6 +1059,55 @@ index c019949..388fdd1 100644 KM_TYPE_NR }; +diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h +index 3a32af4..c8def8a 100644 +--- a/arch/arm/include/asm/page.h ++++ b/arch/arm/include/asm/page.h +@@ -122,7 +122,7 @@ struct cpu_user_fns { + void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr); + void (*cpu_copy_user_highpage)(struct page *to, struct page *from, + unsigned long vaddr); +-}; ++} __no_const; + + #ifdef MULTI_USER + extern struct cpu_user_fns cpu_user; +diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h +index d65b2f5..9d87555 100644 +--- a/arch/arm/include/asm/system.h ++++ b/arch/arm/include/asm/system.h +@@ -86,6 +86,8 @@ void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, + + #define xchg(ptr,x) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) ++#define xchg_unchecked(ptr,x) \ ++ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + + extern asmlinkage void __backtrace(void); + extern asmlinkage void c_backtrace(unsigned long fp, int pmode); +@@ -98,7 +100,7 @@ extern int cpu_architecture(void); + extern void cpu_init(void); + + void arm_machine_restart(char mode, const char *cmd); +-extern void (*arm_pm_restart)(char str, const char *cmd); ++extern void (*arm_pm_restart)(char str, const char *cmd) __noreturn; + + #define UDBG_UNDEFINED (1 << 0) + #define UDBG_SYSCALL (1 << 1) +@@ -505,6 +507,13 @@ static inline unsigned long long __cmpxchg64_mb(volatile void *ptr, + + #endif /* __LINUX_ARM_ARCH__ >= 6 */ + ++#define _ASM_EXTABLE(from, to) \ ++" .pushsection __ex_table,\"a\"\n"\ ++" .align 3\n" \ ++" .long " #from ", " #to"\n" \ ++" .popsection" ++ ++ + #endif /* __ASSEMBLY__ */ + + #define arch_align_stack(x) (x) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 1d6bd40..fba0cb9 100644 --- a/arch/arm/include/asm/uaccess.h @@ -825,6 +1195,69 @@ index ba8ccfe..2dc34dc 100644 #ifndef __ARMEB__ .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} #else /* ! __ARMEB__ */ +diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c +index 61f90d3..771ab27 100644 +--- a/arch/arm/kernel/process.c ++++ b/arch/arm/kernel/process.c +@@ -83,7 +83,7 @@ static int __init hlt_setup(char *__unused) + __setup("nohlt", nohlt_setup); + __setup("hlt", hlt_setup); + +-void arm_machine_restart(char mode, const char *cmd) ++__noreturn void arm_machine_restart(char mode, const char *cmd) + { + /* + * Clean and disable cache, and turn off interrupts +@@ -117,7 +117,7 @@ void arm_machine_restart(char mode, const char *cmd) + void (*pm_power_off)(void); + EXPORT_SYMBOL(pm_power_off); + +-void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart; ++void (*arm_pm_restart)(char str, const char *cmd) __noreturn = arm_machine_restart; + EXPORT_SYMBOL_GPL(arm_pm_restart); + + +@@ -195,6 +195,7 @@ __setup("reboot=", reboot_setup); + + void machine_halt(void) + { ++ BUG(); + } + + +@@ -202,6 +203,7 @@ void machine_power_off(void) + { + if (pm_power_off) + pm_power_off(); ++ BUG(); + } + + void machine_restart(char *cmd) +diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c +index c6c57b6..0c3b29e 100644 +--- a/arch/arm/kernel/setup.c ++++ b/arch/arm/kernel/setup.c +@@ -92,16 +92,16 @@ EXPORT_SYMBOL(elf_hwcap); + struct processor processor; + #endif + #ifdef MULTI_TLB +-struct cpu_tlb_fns cpu_tlb; ++struct cpu_tlb_fns cpu_tlb __read_only; + #endif + #ifdef MULTI_USER +-struct cpu_user_fns cpu_user; ++struct cpu_user_fns cpu_user __read_only; + #endif + #ifdef MULTI_CACHE +-struct cpu_cache_fns cpu_cache; ++struct cpu_cache_fns cpu_cache __read_only; + #endif + #ifdef CONFIG_OUTER_CACHE +-struct outer_cache_fns outer_cache; ++struct outer_cache_fns outer_cache __read_only; + #endif + + struct stack { diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3f361a7..6e806e1 100644 --- a/arch/arm/kernel/traps.c @@ -847,6 +1280,29 @@ index 3f361a7..6e806e1 100644 do_exit(SIGSEGV); } +diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S +index aecf87df..bed731b 100644 +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -74,14 +74,18 @@ SECTIONS + #ifndef CONFIG_XIP_KERNEL + __init_begin = _stext; + INIT_DATA ++ EXIT_TEXT ++ EXIT_DATA + . = ALIGN(PAGE_SIZE); + __init_end = .; + #endif + } + + /DISCARD/ : { /* Exit code and data */ ++#ifdef CONFIG_XIP_KERNEL + EXIT_TEXT + EXIT_DATA ++#endif + *(.exitcall.exit) + *(.discard) + *(.ARM.exidx.exit.text) diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index e4fe124..0fc246b 100644 --- a/arch/arm/lib/copy_from_user.S @@ -874,6 +1330,18 @@ index e4fe124..0fc246b 100644 .section .fixup,"ax" .align 0 +diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S +index 6ee2f67..d1cce76 100644 +--- a/arch/arm/lib/copy_page.S ++++ b/arch/arm/lib/copy_page.S +@@ -10,6 +10,7 @@ + * ASM optimised string functions + */ + #include <linux/linkage.h> ++#include <linux/const.h> + #include <asm/assembler.h> + #include <asm/asm-offsets.h> + #include <asm/cache.h> diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index 1a71e15..ac7b258 100644 --- a/arch/arm/lib/copy_to_user.S @@ -1076,7 +1544,7 @@ index c83fdc8..ab9fc44 100644 .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c -index 3191cd6..c0739db 100644 +index 3191cd6..c322981 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -166,6 +166,13 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, @@ -1127,6 +1595,27 @@ index 3191cd6..c0739db 100644 /* * First Level Translation Fault Handler * +@@ -569,6 +603,20 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) + const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); + struct siginfo info; + ++#ifdef CONFIG_PAX_REFCOUNT ++ if (fsr_fs(ifsr) == 2) { ++ unsigned int bkpt; ++ ++ if (!probe_kernel_address((unsigned int *)addr, bkpt) && bkpt == 0xe12f1073) { ++ current->thread.error_code = ifsr; ++ current->thread.trap_no = 0; ++ pax_report_refcount_overflow(regs); ++ fixup_exception(regs); ++ return; ++ } ++ } ++#endif ++ + if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) + return; + diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index f5abc51..7ec524c 100644 --- a/arch/arm/mm/mmap.c @@ -1193,6 +1682,22 @@ index 8d97db2..b66cfa5 100644 .enter = s3c_pm_enter, .prepare = s3c_pm_prepare, .finish = s3c_pm_finish, +diff --git a/arch/avr32/include/asm/cache.h b/arch/avr32/include/asm/cache.h +index d3cf35a..0ba6053 100644 +--- a/arch/avr32/include/asm/cache.h ++++ b/arch/avr32/include/asm/cache.h +@@ -1,8 +1,10 @@ + #ifndef __ASM_AVR32_CACHE_H + #define __ASM_AVR32_CACHE_H + ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT 5 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + /* + * Memory returned by kmalloc() may be used for DMA, so we must make diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h index d5d1d41..856e2ed 100644 --- a/arch/avr32/include/asm/elf.h @@ -1285,6 +1790,26 @@ index b61d86d..e292c7f 100644 if (exception_trace && printk_ratelimit()) printk("%s%s[%d]: segfault at %08lx pc %08lx " "sp %08lx ecr %lu\n", +diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h +index 93f6c63..d144953 100644 +--- a/arch/blackfin/include/asm/cache.h ++++ b/arch/blackfin/include/asm/cache.h +@@ -7,12 +7,14 @@ + #ifndef __ARCH_BLACKFIN_CACHE_H + #define __ARCH_BLACKFIN_CACHE_H + ++#include <linux/const.h> ++ + /* + * Bytes per L1 cache line + * Blackfin loads 32 bytes for cache + */ + #define L1_CACHE_SHIFT 5 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + #define SMP_CACHE_BYTES L1_CACHE_BYTES + + #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index cce79d0..c406c85 100644 --- a/arch/blackfin/kernel/kgdb.c @@ -1311,6 +1836,39 @@ index 8837be4..b2fb413 100644 .enter = bfin_pm_enter, .valid = bfin_pm_valid, }; +diff --git a/arch/cris/include/arch-v10/arch/cache.h b/arch/cris/include/arch-v10/arch/cache.h +index aea2718..3639a60 100644 +--- a/arch/cris/include/arch-v10/arch/cache.h ++++ b/arch/cris/include/arch-v10/arch/cache.h +@@ -1,8 +1,9 @@ + #ifndef _ASM_ARCH_CACHE_H + #define _ASM_ARCH_CACHE_H + ++#include <linux/const.h> + /* Etrax 100LX have 32-byte cache-lines. */ +-#define L1_CACHE_BYTES 32 + #define L1_CACHE_SHIFT 5 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* _ASM_ARCH_CACHE_H */ +diff --git a/arch/cris/include/arch-v32/arch/cache.h b/arch/cris/include/arch-v32/arch/cache.h +index dfc7305..417f5b3 100644 +--- a/arch/cris/include/arch-v32/arch/cache.h ++++ b/arch/cris/include/arch-v32/arch/cache.h +@@ -1,11 +1,12 @@ + #ifndef _ASM_CRIS_ARCH_CACHE_H + #define _ASM_CRIS_ARCH_CACHE_H + ++#include <linux/const.h> + #include <arch/hwregs/dma.h> + + /* A cache-line is 32 bytes. */ +-#define L1_CACHE_BYTES 32 + #define L1_CACHE_SHIFT 5 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + void flush_dma_list(dma_descr_data *descr); + void flush_dma_descr(dma_descr_data *descr, int flush_buf); diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 00a57af..c3ef0cd 100644 --- a/arch/frv/include/asm/atomic.h @@ -1332,6 +1890,23 @@ index 00a57af..c3ef0cd 100644 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) { int c, old; +diff --git a/arch/frv/include/asm/cache.h b/arch/frv/include/asm/cache.h +index 7dc0f0f..1e6a620 100644 +--- a/arch/frv/include/asm/cache.h ++++ b/arch/frv/include/asm/cache.h +@@ -12,10 +12,11 @@ + #ifndef __ASM_CACHE_H + #define __ASM_CACHE_H + ++#include <linux/const.h> + + /* bytes per L1 cache line */ + #define L1_CACHE_SHIFT (CONFIG_FRV_L1_CACHE_SHIFT) +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES + diff --git a/arch/frv/include/asm/kmap_types.h b/arch/frv/include/asm/kmap_types.h index f8e16b2..c73ff79 100644 --- a/arch/frv/include/asm/kmap_types.h @@ -1376,6 +1951,22 @@ index 385fd30..6c3d97e 100644 goto success; addr = vma->vm_end; } +diff --git a/arch/h8300/include/asm/cache.h b/arch/h8300/include/asm/cache.h +index c635028..6d9445a 100644 +--- a/arch/h8300/include/asm/cache.h ++++ b/arch/h8300/include/asm/cache.h +@@ -1,8 +1,10 @@ + #ifndef __ARCH_H8300_CACHE_H + #define __ARCH_H8300_CACHE_H + ++#include <linux/const.h> ++ + /* bytes per L1 cache line */ +-#define L1_CACHE_BYTES 4 ++#define L1_CACHE_BYTES _AC(4,UL) + + /* m68k-elf-gcc 2.95.2 doesn't like these */ + diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c index e4a80d8..11a7ea1 100644 --- a/arch/ia64/hp/common/hwsw_iommu.c @@ -1479,6 +2070,27 @@ index 88405cb..de5ca5d 100644 /* Atomic operations are already serializing */ #define smp_mb__before_atomic_dec() barrier() #define smp_mb__after_atomic_dec() barrier() +diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h +index e7482bd..d1c9b8e 100644 +--- a/arch/ia64/include/asm/cache.h ++++ b/arch/ia64/include/asm/cache.h +@@ -1,6 +1,7 @@ + #ifndef _ASM_IA64_CACHE_H + #define _ASM_IA64_CACHE_H + ++#include <linux/const.h> + + /* + * Copyright (C) 1998-2000 Hewlett-Packard Co +@@ -9,7 +10,7 @@ + + /* Bytes per L1 (data) cache line. */ + #define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #ifdef CONFIG_SMP + # define SMP_CACHE_SHIFT L1_CACHE_SHIFT diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 8d3c79c..71b3af6 100644 --- a/arch/ia64/include/asm/dma-mapping.h @@ -1979,6 +2591,22 @@ index 98b6849..8046766 100644 .alloc_coherent = sn_dma_alloc_coherent, .free_coherent = sn_dma_free_coherent, .map_page = sn_dma_map_page, +diff --git a/arch/m32r/include/asm/cache.h b/arch/m32r/include/asm/cache.h +index 40b3ee9..8c2c112 100644 +--- a/arch/m32r/include/asm/cache.h ++++ b/arch/m32r/include/asm/cache.h +@@ -1,8 +1,10 @@ + #ifndef _ASM_M32R_CACHE_H + #define _ASM_M32R_CACHE_H + ++#include <linux/const.h> ++ + /* L1 cache line size */ + #define L1_CACHE_SHIFT 4 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* _ASM_M32R_CACHE_H */ diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c index 82abd15..d95ae5d 100644 --- a/arch/m32r/lib/usercopy.c @@ -2003,6 +2631,41 @@ index 82abd15..d95ae5d 100644 prefetchw(to); if (access_ok(VERIFY_READ, from, n)) __copy_user_zeroing(to,from,n); +diff --git a/arch/m68k/include/asm/cache.h b/arch/m68k/include/asm/cache.h +index ecafbe1..432c3e4 100644 +--- a/arch/m68k/include/asm/cache.h ++++ b/arch/m68k/include/asm/cache.h +@@ -4,9 +4,11 @@ + #ifndef __ARCH_M68K_CACHE_H + #define __ARCH_M68K_CACHE_H + ++#include <linux/const.h> ++ + /* bytes per L1 cache line */ + #define L1_CACHE_SHIFT 4 +-#define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES + +diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h +index c209c47..2ba96e2 100644 +--- a/arch/microblaze/include/asm/cache.h ++++ b/arch/microblaze/include/asm/cache.h +@@ -13,11 +13,12 @@ + #ifndef _ASM_MICROBLAZE_CACHE_H + #define _ASM_MICROBLAZE_CACHE_H + ++#include <linux/const.h> + #include <asm/registers.h> + + #define L1_CACHE_SHIFT 2 + /* word-granular cache in microblaze */ +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define SMP_CACHE_BYTES L1_CACHE_BYTES + diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index fd7620f..63d73a6 100644 --- a/arch/mips/Kconfig @@ -2073,6 +2736,23 @@ index 09e7128..111035b 100644 #endif /* CONFIG_64BIT */ /* +diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h +index 37f175c..c7a3065 100644 +--- a/arch/mips/include/asm/cache.h ++++ b/arch/mips/include/asm/cache.h +@@ -9,10 +9,11 @@ + #ifndef _ASM_CACHE_H + #define _ASM_CACHE_H + ++#include <linux/const.h> + #include <kmalloc.h> + + #define L1_CACHE_SHIFT CONFIG_MIPS_L1_CACHE_SHIFT +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define SMP_CACHE_SHIFT L1_CACHE_SHIFT + #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 7990694..4e93acf 100644 --- a/arch/mips/include/asm/elf.h @@ -2297,6 +2977,26 @@ index e97a7a2..f18f5b0 100644 /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate +diff --git a/arch/mn10300/proc-mn103e010/include/proc/cache.h b/arch/mn10300/proc-mn103e010/include/proc/cache.h +index bdc1f9a..e8de5c5 100644 +--- a/arch/mn10300/proc-mn103e010/include/proc/cache.h ++++ b/arch/mn10300/proc-mn103e010/include/proc/cache.h +@@ -11,12 +11,14 @@ + #ifndef _ASM_PROC_CACHE_H + #define _ASM_PROC_CACHE_H + ++#include <linux/const.h> ++ + /* L1 cache */ + + #define L1_CACHE_NWAYS 4 /* number of ways in caches */ + #define L1_CACHE_NENTRIES 256 /* number of entries in each way */ +-#define L1_CACHE_BYTES 16 /* bytes per entry */ + #define L1_CACHE_SHIFT 4 /* shift for bytes per entry */ ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per entry */ + #define L1_CACHE_WAYDISP 0x1000 /* displacement of one way from the next */ + + #define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */ diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 8bc9e96..26554f8 100644 --- a/arch/parisc/include/asm/atomic.h @@ -2318,6 +3018,34 @@ index 8bc9e96..26554f8 100644 #else /* CONFIG_64BIT */ #include <asm-generic/atomic64.h> +diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h +index 32c2cca..a7b3a64 100644 +--- a/arch/parisc/include/asm/cache.h ++++ b/arch/parisc/include/asm/cache.h +@@ -5,6 +5,7 @@ + #ifndef __ARCH_PARISC_CACHE_H + #define __ARCH_PARISC_CACHE_H + ++#include <linux/const.h> + + /* + * PA 2.0 processors have 64-byte cachelines; PA 1.1 processors have +@@ -15,13 +16,13 @@ + * just ruin performance. + */ + #ifdef CONFIG_PA20 +-#define L1_CACHE_BYTES 64 + #define L1_CACHE_SHIFT 6 + #else +-#define L1_CACHE_BYTES 32 + #define L1_CACHE_SHIFT 5 + #endif + ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) ++ + #ifndef __ASSEMBLY__ + + #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 9c802eb..0592e41 100644 --- a/arch/parisc/include/asm/elf.h @@ -2693,6 +3421,27 @@ index c107b74..409dc0f 100644 CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__ ifeq ($(CONFIG_PPC64),y) +diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h +index 81de6eb..d5d0e24 100644 +--- a/arch/powerpc/include/asm/cache.h ++++ b/arch/powerpc/include/asm/cache.h +@@ -3,6 +3,7 @@ + + #ifdef __KERNEL__ + ++#include <linux/const.h> + + /* bytes per L1 cache line */ + #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) +@@ -18,7 +19,7 @@ + #define L1_CACHE_SHIFT 7 + #endif + +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define SMP_CACHE_BYTES L1_CACHE_BYTES + diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index 6d94d27..50d4cad 100644 --- a/arch/powerpc/include/asm/device.h @@ -3263,6 +4012,34 @@ index a4c8b38..1b09ad9 100644 .alloc_coherent = ibmebus_alloc_coherent, .free_coherent = ibmebus_free_coherent, .map_sg = ibmebus_map_sg, +diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c +index 8564a41..67f3471 100644 +--- a/arch/powerpc/kernel/irq.c ++++ b/arch/powerpc/kernel/irq.c +@@ -490,9 +490,6 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, + host->ops = ops; + host->of_node = of_node_get(of_node); + +- if (host->ops->match == NULL) +- host->ops->match = default_irq_host_match; +- + spin_lock_irqsave(&irq_big_lock, flags); + + /* If it's a legacy controller, check for duplicates and +@@ -567,7 +564,12 @@ struct irq_host *irq_find_host(struct device_node *node) + */ + spin_lock_irqsave(&irq_big_lock, flags); + list_for_each_entry(h, &irq_hosts, link) +- if (h->ops->match(h, node)) { ++ if (h->ops->match) { ++ if (h->ops->match(h, node)) { ++ found = h; ++ break; ++ } ++ } else if (default_irq_host_match(h, node)) { + found = h; + break; + } diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 641c74b..8339ad7 100644 --- a/arch/powerpc/kernel/kgdb.c @@ -4024,6 +4801,22 @@ index ae7c8f9..3f01a0c 100644 #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() #define smp_mb__before_atomic_inc() smp_mb() +diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h +index 9b86681..c5140db 100644 +--- a/arch/s390/include/asm/cache.h ++++ b/arch/s390/include/asm/cache.h +@@ -11,8 +11,10 @@ + #ifndef __ARCH_S390_CACHE_H + #define __ARCH_S390_CACHE_H + +-#define L1_CACHE_BYTES 256 ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT 8 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define __read_mostly __attribute__((__section__(".data.read_mostly"))) + diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index e885442..e3a2817 100644 --- a/arch/s390/include/asm/elf.h @@ -4280,6 +5073,21 @@ index 0ab74ae..c8b68f9 100644 mm->get_unmapped_area = s390_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } +diff --git a/arch/score/include/asm/cache.h b/arch/score/include/asm/cache.h +index ae3d59f..f65f075 100644 +--- a/arch/score/include/asm/cache.h ++++ b/arch/score/include/asm/cache.h +@@ -1,7 +1,9 @@ + #ifndef _ASM_SCORE_CACHE_H + #define _ASM_SCORE_CACHE_H + ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT 4 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* _ASM_SCORE_CACHE_H */ diff --git a/arch/score/include/asm/system.h b/arch/score/include/asm/system.h index 589d5c7..669e274 100644 --- a/arch/score/include/asm/system.h @@ -4319,6 +5127,23 @@ index d936c1a..304a252 100644 .enter = hp6x0_pm_enter, .valid = suspend_valid_only_mem, }; +diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h +index 02df18e..ae3a793 100644 +--- a/arch/sh/include/asm/cache.h ++++ b/arch/sh/include/asm/cache.h +@@ -9,10 +9,11 @@ + #define __ASM_SH_CACHE_H + #ifdef __KERNEL__ + ++#include <linux/const.h> + #include <linux/init.h> + #include <cpu/cache.h> + +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define __read_mostly __attribute__((__section__(".data.read_mostly"))) + diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 8a8a993..7b3079b 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c @@ -4461,17 +5286,19 @@ index 113225b..7fd04e7 100644 VMLINUX_MAIN += $(patsubst %/, %/lib.a, $(libs-y)) $(libs-y) VMLINUX_MAIN += $(drivers-y) $(net-y) -diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h -index 8ff83d8..4a459c2 100644 ---- a/arch/sparc/include/asm/atomic.h -+++ b/arch/sparc/include/asm/atomic.h -@@ -4,5 +4,6 @@ - #include <asm/atomic_64.h> - #else - #include <asm/atomic_32.h> +diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h +index f0d343c..cf36e68 100644 +--- a/arch/sparc/include/asm/atomic_32.h ++++ b/arch/sparc/include/asm/atomic_32.h +@@ -13,6 +13,8 @@ + + #include <linux/types.h> + +#include <asm-generic/atomic64.h> - #endif - #endif ++ + #ifdef __KERNEL__ + + #include <asm/system.h> diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index f5cc06f..f858d47 100644 --- a/arch/sparc/include/asm/atomic_64.h @@ -4669,15 +5496,18 @@ index f5cc06f..f858d47 100644 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h -index 41f85ae..fb54d5e 100644 +index 41f85ae..73b80b5 100644 --- a/arch/sparc/include/asm/cache.h +++ b/arch/sparc/include/asm/cache.h -@@ -8,7 +8,7 @@ +@@ -7,8 +7,10 @@ + #ifndef _SPARC_CACHE_H #define _SPARC_CACHE_H ++#include <linux/const.h> ++ #define L1_CACHE_SHIFT 5 -#define L1_CACHE_BYTES 32 -+#define L1_CACHE_BYTES 32UL ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))) #ifdef CONFIG_SPARC32 @@ -6965,6 +7795,26 @@ index fc633db..5e1a1c2 100644 include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH) #This will adjust *FLAGS accordingly to the platform. +diff --git a/arch/um/include/asm/cache.h b/arch/um/include/asm/cache.h +index 19e1bdd..3665b77 100644 +--- a/arch/um/include/asm/cache.h ++++ b/arch/um/include/asm/cache.h +@@ -1,6 +1,7 @@ + #ifndef __UM_CACHE_H + #define __UM_CACHE_H + ++#include <linux/const.h> + + #if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) + # define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) +@@ -12,6 +13,6 @@ + # define L1_CACHE_SHIFT 5 + #endif + +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h index 6c03acd..a5e0215 100644 --- a/arch/um/include/asm/kmap_types.h @@ -15884,7 +16734,7 @@ index c097e7d..c689cf4 100644 /* * End of kprobes section diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S -index 34a56a9..87790b4 100644 +index 34a56a9..74613c5 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -53,6 +53,8 @@ @@ -16267,7 +17117,7 @@ index 34a56a9..87790b4 100644 * We entered an interrupt context - irqs are off: */ 2: TRACE_IRQS_OFF -+ pax_force_retaddr ++ pax_force_retaddr_bts ret CFI_ENDPROC -END(save_args) @@ -27403,6 +28253,67 @@ index f9153a3..51eab3d 100644 struct trap_info; void xen_copy_trap_info(struct trap_info *traps); +diff --git a/arch/xtensa/variants/dc232b/include/variant/core.h b/arch/xtensa/variants/dc232b/include/variant/core.h +index 525bd3d..ef888b1 100644 +--- a/arch/xtensa/variants/dc232b/include/variant/core.h ++++ b/arch/xtensa/variants/dc232b/include/variant/core.h +@@ -119,9 +119,9 @@ + ----------------------------------------------------------------------*/ + + #define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */ +-#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */ + #define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */ + #define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */ ++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ + + #define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */ + #define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */ +diff --git a/arch/xtensa/variants/fsf/include/variant/core.h b/arch/xtensa/variants/fsf/include/variant/core.h +index 2f33760..835e50a 100644 +--- a/arch/xtensa/variants/fsf/include/variant/core.h ++++ b/arch/xtensa/variants/fsf/include/variant/core.h +@@ -11,6 +11,7 @@ + #ifndef _XTENSA_CORE_H + #define _XTENSA_CORE_H + ++#include <linux/const.h> + + /**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED +@@ -112,9 +113,9 @@ + ----------------------------------------------------------------------*/ + + #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ +-#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ + #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ + #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ ++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ + + #define XCHAL_ICACHE_SIZE 8192 /* I-cache size in bytes or 0 */ + #define XCHAL_DCACHE_SIZE 8192 /* D-cache size in bytes or 0 */ +diff --git a/arch/xtensa/variants/s6000/include/variant/core.h b/arch/xtensa/variants/s6000/include/variant/core.h +index af00795..2bb8105 100644 +--- a/arch/xtensa/variants/s6000/include/variant/core.h ++++ b/arch/xtensa/variants/s6000/include/variant/core.h +@@ -11,6 +11,7 @@ + #ifndef _XTENSA_CORE_CONFIGURATION_H + #define _XTENSA_CORE_CONFIGURATION_H + ++#include <linux/const.h> + + /**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED +@@ -118,9 +119,9 @@ + ----------------------------------------------------------------------*/ + + #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ +-#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ + #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ + #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ ++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ + + #define XCHAL_ICACHE_SIZE 32768 /* I-cache size in bytes or 0 */ + #define XCHAL_DCACHE_SIZE 32768 /* D-cache size in bytes or 0 */ diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 15c6308..96e83c2 100644 --- a/block/blk-integrity.c @@ -36715,7 +37626,7 @@ index 968cb14..f0ad2e4 100644 "raid1:%s: read error corrected " "(%d sectors at %llu on %s)\n", diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c -index 1b4e232..cf0f534 100644 +index 1b4e232..cf0f534b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1255,7 +1255,7 @@ static void end_sync_read(struct bio *bio, int error) @@ -38118,6 +39029,12628 @@ index ab68886..ca405e8 100644 MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ MODULE_PARM_DESC(X, desc); #else +diff --git a/drivers/net/benet/Makefile b/drivers/net/benet/Makefile +index a60cd80..0ed11ef 100644 +--- a/drivers/net/benet/Makefile ++++ b/drivers/net/benet/Makefile +@@ -1,7 +1,9 @@ + # +-# Makefile to build the network driver for ServerEngine's BladeEngine. ++# Makefile to build the be2net network driver + # + ++EXTRA_CFLAGS += -DCONFIG_PALAU ++ + obj-$(CONFIG_BE2NET) += be2net.o + +-be2net-y := be_main.o be_cmds.o be_ethtool.o ++be2net-y := be_main.o be_cmds.o be_ethtool.o be_compat.o be_misc.o +diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h +index 5c74ff0..7382603 100644 +--- a/drivers/net/benet/be.h ++++ b/drivers/net/benet/be.h +@@ -1,18 +1,18 @@ + /* +- * Copyright (C) 2005 - 2009 ServerEngines ++ * Copyright (C) 2005 - 2011 Emulex + * 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 ++ * 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 ++ * linux-drivers@emulex.com + * +- * ServerEngines +- * 209 N. Fair Oaks Ave +- * Sunnyvale, CA 94085 ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 + */ + + #ifndef BE_H +@@ -29,32 +29,53 @@ + #include <linux/workqueue.h> + #include <linux/interrupt.h> + #include <linux/firmware.h> ++#include <linux/jhash.h> ++#ifndef CONFIG_PALAU ++#include <linux/inet_lro.h> ++#endif + ++#ifdef CONFIG_PALAU ++#include "be_compat.h" ++#endif + #include "be_hw.h" + +-#define DRV_VER "2.101.205" ++#ifdef CONFIG_PALAU ++#include "version.h" ++#define DRV_VER STR_BE_MAJOR "." STR_BE_MINOR "."\ ++ STR_BE_BUILD "." STR_BE_BRANCH ++#else ++#define DRV_VER "2.0.348" ++#endif + #define DRV_NAME "be2net" +-#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" +-#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" +-#define OC_NAME "Emulex OneConnect 10Gbps NIC" +-#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)" +-#define DRV_DESC BE_NAME "Driver" ++#define BE_NAME "Emulex BladeEngine2" ++#define BE3_NAME "Emulex BladeEngine3" ++#define OC_NAME "Emulex OneConnect" ++#define OC_NAME_BE OC_NAME "(be3)" ++#define OC_NAME_LANCER OC_NAME "(Lancer)" ++#define DRV_DESC "Emulex OneConnect 10Gbps NIC Driver" + +-#define BE_VENDOR_ID 0x19a2 ++#define BE_VENDOR_ID 0x19a2 ++#define EMULEX_VENDOR_ID 0x10df + #define BE_DEVICE_ID1 0x211 + #define BE_DEVICE_ID2 0x221 +-#define OC_DEVICE_ID1 0x700 +-#define OC_DEVICE_ID2 0x701 +-#define OC_DEVICE_ID3 0x710 ++#define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */ ++#define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */ ++#define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ ++ ++#define OC_SUBSYS_DEVICE_ID1 0xE602 ++#define OC_SUBSYS_DEVICE_ID2 0xE642 ++#define OC_SUBSYS_DEVICE_ID3 0xE612 ++#define OC_SUBSYS_DEVICE_ID4 0xE652 + + static inline char *nic_name(struct pci_dev *pdev) + { + switch (pdev->device) { + case OC_DEVICE_ID1: +- case OC_DEVICE_ID2: + return OC_NAME; ++ case OC_DEVICE_ID2: ++ return OC_NAME_BE; + case OC_DEVICE_ID3: +- return OC_NAME1; ++ return OC_NAME_LANCER; + case BE_DEVICE_ID2: + return BE3_NAME; + default: +@@ -63,7 +84,7 @@ static inline char *nic_name(struct pci_dev *pdev) + } + + /* Number of bytes of an RX frame that are copied to skb->data */ +-#define BE_HDR_LEN 64 ++#define BE_HDR_LEN ((u16) 64) + #define BE_MAX_JUMBO_FRAME_SIZE 9018 + #define BE_MIN_MTU 256 + +@@ -79,10 +100,24 @@ static inline char *nic_name(struct pci_dev *pdev) + #define MCC_Q_LEN 128 /* total size not to exceed 8 pages */ + #define MCC_CQ_LEN 256 + ++#define MAX_RSS_QS 4 /* BE limit is 4 queues/port */ ++ ++#define MAX_RX_QS (MAX_RSS_QS + 1) ++ ++#ifdef MQ_TX ++#define MAX_TX_QS 8 ++#else ++#define MAX_TX_QS 1 ++#endif ++ ++#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RSS qs + 1 def Rx + Tx */ + #define BE_NAPI_WEIGHT 64 +-#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ ++#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ + #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) + ++#define BE_MAX_LRO_DESCRIPTORS 16 ++#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS)) ++ + #define FW_VER_LEN 32 + + struct be_dma_mem { +@@ -127,6 +162,11 @@ static inline void *queue_tail_node(struct be_queue_info *q) + return q->dma_mem.va + q->tail * q->entry_size; + } + ++static inline void *queue_index_node(struct be_queue_info *q, u16 index) ++{ ++ return q->dma_mem.va + index * q->entry_size; ++} ++ + static inline void queue_head_inc(struct be_queue_info *q) + { + index_inc(&q->head, q->len); +@@ -137,6 +177,7 @@ static inline void queue_tail_inc(struct be_queue_info *q) + index_inc(&q->tail, q->len); + } + ++ + struct be_eq_obj { + struct be_queue_info q; + char desc[32]; +@@ -146,6 +187,7 @@ struct be_eq_obj { + u16 min_eqd; /* in usecs */ + u16 max_eqd; /* in usecs */ + u16 cur_eqd; /* in usecs */ ++ u8 eq_idx; + + struct napi_struct napi; + }; +@@ -153,49 +195,20 @@ struct be_eq_obj { + struct be_mcc_obj { + struct be_queue_info q; + struct be_queue_info cq; ++ bool rearm_cq; + }; + +-struct be_drvr_stats { ++struct be_tx_stats { + u32 be_tx_reqs; /* number of TX requests initiated */ + u32 be_tx_stops; /* number of times TX Q was stopped */ +- u32 be_fwd_reqs; /* number of send reqs through forwarding i/f */ + u32 be_tx_wrbs; /* number of tx WRBs used */ +- u32 be_tx_events; /* number of tx completion events */ + u32 be_tx_compl; /* number of tx completion entries processed */ + ulong be_tx_jiffies; + u64 be_tx_bytes; + u64 be_tx_bytes_prev; + u64 be_tx_pkts; + u32 be_tx_rate; +- +- u32 cache_barrier[16]; +- +- u32 be_ethrx_post_fail;/* number of ethrx buffer alloc failures */ +- u32 be_polls; /* number of times NAPI called poll function */ +- u32 be_rx_events; /* number of ucast rx completion events */ +- u32 be_rx_compl; /* number of rx completion entries processed */ +- ulong be_rx_jiffies; +- u64 be_rx_bytes; +- u64 be_rx_bytes_prev; +- u64 be_rx_pkts; +- u32 be_rx_rate; +- /* number of non ether type II frames dropped where +- * frame len > length field of Mac Hdr */ +- u32 be_802_3_dropped_frames; +- /* number of non ether type II frames malformed where +- * in frame len < length field of Mac Hdr */ +- u32 be_802_3_malformed_frames; +- u32 be_rxcp_err; /* Num rx completion entries w/ err set. */ +- ulong rx_fps_jiffies; /* jiffies at last FPS calc */ +- u32 be_rx_frags; +- u32 be_prev_rx_frags; +- u32 be_rx_fps; /* Rx frags per second */ +-}; +- +-struct be_stats_obj { +- struct be_drvr_stats drvr_stats; +- struct net_device_stats net_stats; +- struct be_dma_mem cmd; ++ u32 be_ipv6_ext_hdr_tx_drop; + }; + + struct be_tx_obj { +@@ -203,23 +216,124 @@ struct be_tx_obj { + struct be_queue_info cq; + /* Remember the skbs that were transmitted */ + struct sk_buff *sent_skb_list[TX_Q_LEN]; ++ struct be_tx_stats stats; + }; + + /* Struct to remember the pages posted for rx frags */ + struct be_rx_page_info { + struct page *page; +- dma_addr_t bus; ++ DEFINE_DMA_UNMAP_ADDR(bus); + u16 page_offset; + bool last_page_user; + }; + ++struct be_rx_stats { ++ u32 rx_post_fail;/* number of ethrx buffer alloc failures */ ++ u32 rx_polls; /* number of times NAPI called poll function */ ++ u32 rx_events; /* number of ucast rx completion events */ ++ u32 rx_compl; /* number of rx completion entries processed */ ++ ulong rx_jiffies; ++ u64 rx_bytes; ++ u64 rx_bytes_prev; ++ u64 rx_pkts; ++ u32 rx_rate; ++ u32 rx_mcast_pkts; ++ u32 rxcp_err; /* Num rx completion entries w/ err set. */ ++ ulong rx_fps_jiffies; /* jiffies at last FPS calc */ ++ u32 rx_frags; ++ u32 prev_rx_frags; ++ u32 rx_fps; /* Rx frags per second */ ++ u32 rx_drops_no_frags; ++}; ++ ++struct be_rx_compl_info { ++ u32 rss_hash; ++ u16 vlan_tag; ++ u16 pkt_size; ++ u16 rxq_idx; ++ u16 port; ++ u8 vlanf; ++ u8 num_rcvd; ++ u8 err; ++ u8 ipf; ++ u8 tcpf; ++ u8 udpf; ++ u8 ip_csum; ++ u8 l4_csum; ++ u8 ipv6; ++ u8 vtm; ++ u8 pkt_type; ++}; ++ + struct be_rx_obj { ++ struct be_adapter *adapter; + struct be_queue_info q; + struct be_queue_info cq; +- struct be_rx_page_info page_info_tbl[RX_Q_LEN]; ++ struct be_rx_compl_info rxcp; ++ struct be_rx_page_info *page_info_tbl; ++ struct net_lro_mgr lro_mgr; ++ struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS]; ++ struct be_eq_obj rx_eq; ++ struct be_rx_stats stats; ++ u8 rss_id; ++ bool rx_post_starved; /* Zero rx frags have been posted to BE */ ++ u16 prev_frag_idx; ++ u32 cache_line_barrier[16]; + }; + +-#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */ ++struct be_drv_stats { ++ u32 be_on_die_temperature; ++ u32 be_tx_events; ++ u32 eth_red_drops; ++ u32 rx_drops_no_pbuf; ++ u32 rx_drops_no_txpb; ++ u32 rx_drops_no_erx_descr; ++ u32 rx_drops_no_tpre_descr; ++ u32 rx_drops_too_many_frags; ++ u32 rx_drops_invalid_ring; ++ u32 forwarded_packets; ++ u32 rx_drops_mtu; ++ u32 rx_crc_errors; ++ u32 rx_alignment_symbol_errors; ++ u32 rx_pause_frames; ++ u32 rx_priority_pause_frames; ++ u32 rx_control_frames; ++ u32 rx_in_range_errors; ++ u32 rx_out_range_errors; ++ u32 rx_frame_too_long; ++ u32 rx_address_match_errors; ++ u32 rx_dropped_too_small; ++ u32 rx_dropped_too_short; ++ u32 rx_dropped_header_too_small; ++ u32 rx_dropped_tcp_length; ++ u32 rx_dropped_runt; ++ u32 rx_ip_checksum_errs; ++ u32 rx_tcp_checksum_errs; ++ u32 rx_udp_checksum_errs; ++ u32 rx_switched_unicast_packets; ++ u32 rx_switched_multicast_packets; ++ u32 rx_switched_broadcast_packets; ++ u32 tx_pauseframes; ++ u32 tx_priority_pauseframes; ++ u32 tx_controlframes; ++ u32 rxpp_fifo_overflow_drop; ++ u32 rx_input_fifo_overflow_drop; ++ u32 pmem_fifo_overflow_drop; ++ u32 jabber_events; ++}; ++ ++struct be_vf_cfg { ++ unsigned char vf_mac_addr[ETH_ALEN]; ++ u32 vf_if_handle; ++ u32 vf_pmac_id; ++ u16 vf_def_vid; ++ u16 vf_vlan_tag; ++ u32 vf_tx_rate; ++}; ++ ++#define BE_INVALID_PMAC_ID 0xffffffff ++#define BE_FLAGS_DCBX (1 << 16) ++ + struct be_adapter { + struct pci_dev *pdev; + struct net_device *netdev; +@@ -228,7 +342,7 @@ struct be_adapter { + u8 __iomem *db; /* Door Bell */ + u8 __iomem *pcicfg; /* PCI config space */ + +- spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ ++ struct mutex mbox_lock; /* For serializing mbox cmds to BE card */ + struct be_dma_mem mbox_mem; + /* Mbox mem is adjusted to align to 16 bytes. The allocated addr + * is stored for freeing purpose */ +@@ -238,66 +352,121 @@ struct be_adapter { + spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ + spinlock_t mcc_cq_lock; + +- struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS]; +- bool msix_enabled; ++ struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; ++ u32 num_msix_vec; + bool isr_registered; + + /* TX Rings */ + struct be_eq_obj tx_eq; +- struct be_tx_obj tx_obj; ++ struct be_tx_obj tx_obj[MAX_TX_QS]; ++ u8 num_tx_qs; ++ u8 prio_tc_map[MAX_TX_QS]; /* prio_tc_map[prio] => tc-id */ ++ u8 tc_txq_map[MAX_TX_QS]; /* tc_txq_map[tc-id] => txq index */ + + u32 cache_line_break[8]; + + /* Rx rings */ +- struct be_eq_obj rx_eq; +- struct be_rx_obj rx_obj; ++ struct be_rx_obj rx_obj[MAX_RX_QS]; /* one default non-rss Q */ ++ u32 num_rx_qs; ++ ++ struct be_dma_mem stats_cmd; ++ struct net_device_stats net_stats; ++ struct be_drv_stats drv_stats; + u32 big_page_size; /* Compounded page size shared by rx wrbs */ +- bool rx_post_starved; /* Zero rx frags have been posted to BE */ + + struct vlan_group *vlan_grp; +- u16 num_vlans; ++ u16 vlans_added; ++ u16 max_vlans; /* Number of vlans supported */ + u8 vlan_tag[VLAN_GROUP_ARRAY_LEN]; ++ u8 vlan_prio_bmap; /* Available priority BitMap */ ++ u16 recommended_prio; /* Recommended Priority */ ++ struct be_dma_mem rx_filter; + +- struct be_stats_obj stats; + /* Work queue used to perform periodic tasks like getting statistics */ + struct delayed_work work; ++ u16 work_counter; + +- /* Ethtool knobs and info */ +- bool rx_csum; /* BE card must perform rx-checksumming */ ++ u32 flags; ++ bool rx_csum; /* BE card must perform rx-checksumming */ ++ u32 max_rx_coal; + char fw_ver[FW_VER_LEN]; + u32 if_handle; /* Used to configure filtering */ + u32 pmac_id; /* MAC addr handle used by BE card */ ++ u32 beacon_state; /* for set_phys_id */ + +- bool link_up; ++ bool eeh_err; ++ int link_status; + u32 port_num; ++ u32 hba_port_num; + bool promiscuous; +- u32 cap; ++ bool wol; ++ u32 function_mode; ++ u32 function_caps; + u32 rx_fc; /* Rx flow control */ + u32 tx_fc; /* Tx flow control */ ++ bool ue_detected; ++ bool stats_cmd_sent; ++ bool gro_supported; ++ int link_speed; ++ u8 port_type; ++ u8 transceiver; ++ u8 autoneg; + u8 generation; /* BladeEngine ASIC generation */ ++ u32 flash_status; ++ struct completion flash_compl; ++ ++ u8 eq_next_idx; ++ bool be3_native; ++ u16 num_vfs; ++ struct be_vf_cfg *vf_cfg; ++ u8 is_virtfn; ++ u16 pvid; ++ u32 sli_family; ++ u8 port_name[4]; ++ char model_number[32]; + }; + + /* BladeEngine Generation numbers */ + #define BE_GEN2 2 + #define BE_GEN3 3 + +-extern const struct ethtool_ops be_ethtool_ops; ++#define ON 1 ++#define OFF 0 ++#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3) ++#define lancer_A0_chip(adapter) \ ++ (adapter->sli_family == LANCER_A0_SLI_FAMILY) + +-#define drvr_stats(adapter) (&adapter->stats.drvr_stats) ++extern struct ethtool_ops be_ethtool_ops; + +-static inline unsigned int be_pci_func(struct be_adapter *adapter) +-{ +- return PCI_FUNC(adapter->pdev->devfn); +-} ++#define msix_enabled(adapter) (adapter->num_msix_vec > 0) ++#define tx_stats(txo) (&txo->stats) ++#define rx_stats(rxo) (&rxo->stats) + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++#define BE_SET_NETDEV_OPS(netdev, ops) be_netdev_ops_init(netdev, ops) ++#else + #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) ++#endif ++ ++#define for_all_rx_queues(adapter, rxo, i) \ ++ for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs; \ ++ i++, rxo++) ++ ++/* Just skip the first default non-rss queue */ ++#define for_all_rss_queues(adapter, rxo, i) \ ++ for (i = 0, rxo = &adapter->rx_obj[i+1]; i < (adapter->num_rx_qs - 1);\ ++ i++, rxo++) ++ ++#define for_all_tx_queues(adapter, txo, i) \ ++ for (i = 0, txo = &adapter->tx_obj[i]; i < adapter->num_tx_qs; \ ++ i++, txo++) + + #define PAGE_SHIFT_4K 12 + #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) + + /* Returns number of pages spanned by the data starting at the given addr */ +-#define PAGES_4K_SPANNED(_address, size) \ +- ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ ++#define PAGES_4K_SPANNED(_address, size) \ ++ ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ + (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) + + /* Byte offset into the page corresponding to given address */ +@@ -305,7 +474,7 @@ static inline unsigned int be_pci_func(struct be_adapter *adapter) + ((size_t)(addr) & (PAGE_SIZE_4K-1)) + + /* Returns bit offset within a DWORD of a bitfield */ +-#define AMAP_BIT_OFFSET(_struct, field) \ ++#define AMAP_BIT_OFFSET(_struct, field) \ + (((size_t)&(((_struct *)0)->field))%32) + + /* Returns the bit mask of the field that is NOT shifted into location. */ +@@ -356,6 +525,11 @@ static inline void swap_dws(void *wrb, int len) + #endif /* __BIG_ENDIAN */ + } + ++static inline bool vlan_configured(struct be_adapter *adapter) ++{ ++ return adapter->vlan_grp && adapter->vlans_added; ++} ++ + static inline u8 is_tcp_pkt(struct sk_buff *skb) + { + u8 val = 0; +@@ -380,9 +554,65 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) + return val; + } + ++static inline u8 is_ipv6_ext_hdr(struct sk_buff *skb) ++{ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ if (ip_hdr(skb)->version == 6) ++ return ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr); ++ else ++#endif ++ return 0; ++} ++ ++static inline void be_check_sriov_fn_type(struct be_adapter *adapter) ++{ ++ u32 sli_intf; ++ ++ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); ++ adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; ++} ++ ++static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) ++{ ++ u32 addr; ++ ++ addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0); ++ ++ mac[5] = (u8)(addr & 0xFF); ++ mac[4] = (u8)((addr >> 8) & 0xFF); ++ mac[3] = (u8)((addr >> 16) & 0xFF); ++ /* Use the OUI programmed in hardware */ ++ memcpy(mac, adapter->netdev->dev_addr, 3); ++} ++ ++static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ u8 vlan_prio = 0; ++ u16 vlan_tag = 0; ++ ++ vlan_tag = vlan_tx_tag_get(skb); ++ vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; ++ /* If vlan priority provided by OS is NOT in available bmap */ ++ if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) ++ vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | ++ adapter->recommended_prio; ++ ++ return vlan_tag; ++} ++ ++#define be_physfn(adapter) (!adapter->is_virtfn) ++ + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, + u16 num_popped); +-extern void be_link_status_update(struct be_adapter *adapter, bool link_up); ++extern void be_link_status_update(struct be_adapter *adapter, int link_status); + extern void netdev_stats_update(struct be_adapter *adapter); ++extern void be_parse_stats(struct be_adapter *adapter); + extern int be_load_fw(struct be_adapter *adapter, u8 *func); ++ ++#ifdef CONFIG_PALAU ++extern void be_sysfs_create_group(struct be_adapter *adapter); ++extern void be_sysfs_remove_group(struct be_adapter *adapter); ++#endif ++ + #endif /* BE_H */ +diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c +index 28a0eda..b4ca89c 100644 +--- a/drivers/net/benet/be_cmds.c ++++ b/drivers/net/benet/be_cmds.c +@@ -1,30 +1,45 @@ + /* +- * Copyright (C) 2005 - 2009 ServerEngines ++ * Copyright (C) 2005 - 2011 Emulex + * 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 ++ * 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 ++ * linux-drivers@emulex.com + * +- * ServerEngines +- * 209 N. Fair Oaks Ave +- * Sunnyvale, CA 94085 ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 + */ + + #include "be.h" + #include "be_cmds.h" + ++/* Must be a power of 2 or else MODULO will BUG_ON */ ++static int be_get_temp_freq = 64; ++ ++static inline void *embedded_payload(struct be_mcc_wrb *wrb) ++{ ++ return wrb->payload.embedded_payload; ++} ++ + static void be_mcc_notify(struct be_adapter *adapter) + { + struct be_queue_info *mccq = &adapter->mcc_obj.q; + u32 val = 0; + ++ if (adapter->eeh_err) { ++ dev_info(&adapter->pdev->dev, "Error in Card Detected! Cannot issue commands\n"); ++ return; ++ } ++ + val |= mccq->id & DB_MCCQ_RING_ID_MASK; + val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; ++ ++ wmb(); + iowrite32(val, adapter->db + DB_MCCQ_OFFSET); + } + +@@ -59,21 +74,67 @@ static int be_mcc_compl_process(struct be_adapter *adapter, + + compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & + CQE_STATUS_COMPL_MASK; ++ ++ if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) && ++ (compl->tag1 == CMD_SUBSYSTEM_COMMON)) { ++ adapter->flash_status = compl_status; ++ complete(&adapter->flash_compl); ++ } ++ + if (compl_status == MCC_STATUS_SUCCESS) { +- if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) { +- struct be_cmd_resp_get_stats *resp = +- adapter->stats.cmd.va; +- be_dws_le_to_cpu(&resp->hw_stats, +- sizeof(resp->hw_stats)); ++ if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) && ++ (compl->tag1 == CMD_SUBSYSTEM_ETH)) { ++ if (adapter->generation == BE_GEN3) { ++ struct be_cmd_resp_get_stats_v1 *resp = ++ adapter->stats_cmd.va; ++ ++ be_dws_le_to_cpu(&resp->hw_stats, ++ sizeof(resp->hw_stats)); ++ } else { ++ struct be_cmd_resp_get_stats_v0 *resp = ++ adapter->stats_cmd.va; ++ ++ be_dws_le_to_cpu(&resp->hw_stats, ++ sizeof(resp->hw_stats)); ++ } ++ be_parse_stats(adapter); + netdev_stats_update(adapter); ++ adapter->stats_cmd_sent = false; ++ } ++ if (compl->tag0 == ++ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) { ++ struct be_mcc_wrb *mcc_wrb = ++ queue_index_node(&adapter->mcc_obj.q, ++ compl->tag1); ++ struct be_cmd_resp_get_cntl_addnl_attribs *resp = ++ embedded_payload(mcc_wrb); ++ adapter->drv_stats.be_on_die_temperature = ++ resp->on_die_temperature; ++ } ++ } else { ++ if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) ++ be_get_temp_freq = 0; ++ ++ if (compl->tag1 == MCC_WRB_PASS_THRU) ++ goto done; ++ ++ if (compl_status == MCC_STATUS_NOT_SUPPORTED || ++ compl_status == MCC_STATUS_ILLEGAL_REQUEST) ++ goto done; ++ ++ if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) { ++ dev_warn(&adapter->pdev->dev, "This domain(VM) is not " ++ "permitted to execute this cmd (opcode %d)\n", ++ compl->tag0); ++ } else { ++ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & ++ CQE_STATUS_EXTD_MASK; ++ dev_err(&adapter->pdev->dev, "Cmd (opcode %d) failed:" ++ "status %d, extd-status %d\n", ++ compl->tag0, compl_status, extd_status); + } +- } else if (compl_status != MCC_STATUS_NOT_SUPPORTED) { +- extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & +- CQE_STATUS_EXTD_MASK; +- dev_warn(&adapter->pdev->dev, +- "Error in cmd completion: status(compl/extd)=%d/%d\n", +- compl_status, extd_status); + } ++done: + return compl_status; + } + +@@ -82,7 +143,70 @@ static void be_async_link_state_process(struct be_adapter *adapter, + struct be_async_event_link_state *evt) + { + be_link_status_update(adapter, +- evt->port_link_status == ASYNC_EVENT_LINK_UP); ++ ((evt->port_link_status & ~ASYNC_EVENT_LOGICAL) == ++ ASYNC_EVENT_LINK_UP ? LINK_UP : LINK_DOWN)); ++} ++ ++/* Grp5 CoS Priority evt */ ++static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, ++ struct be_async_event_grp5_cos_priority *evt) ++{ ++ if (evt->valid) { ++ adapter->vlan_prio_bmap = evt->available_priority_bmap; ++ adapter->recommended_prio &= ~VLAN_PRIO_MASK; ++ adapter->recommended_prio = ++ evt->reco_default_priority << VLAN_PRIO_SHIFT; ++ } ++} ++ ++/* Grp5 QOS Speed evt */ ++static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, ++ struct be_async_event_grp5_qos_link_speed *evt) ++{ ++ if (evt->physical_port == adapter->hba_port_num) { ++ /* qos_link_speed is in units of 10 Mbps */ ++ adapter->link_speed = evt->qos_link_speed * 10; ++ } ++} ++ ++/*Grp5 PVID evt*/ ++static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, ++ struct be_async_event_grp5_pvid_state *evt) ++{ ++ if (evt->enabled) ++ adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK ; ++ else ++ adapter->pvid = 0; ++} ++ ++static void be_async_grp5_evt_process(struct be_adapter *adapter, ++ u32 trailer, struct be_mcc_compl *evt) ++{ ++ u8 event_type = 0; ++ ++ event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) & ++ ASYNC_TRAILER_EVENT_TYPE_MASK; ++ ++ switch (event_type) { ++ case ASYNC_EVENT_COS_PRIORITY: ++ be_async_grp5_cos_priority_process(adapter, ++ (struct be_async_event_grp5_cos_priority *)evt); ++ break; ++ case ASYNC_EVENT_QOS_SPEED: ++ be_async_grp5_qos_speed_process(adapter, ++ (struct be_async_event_grp5_qos_link_speed *)evt); ++ break; ++ case ASYNC_EVENT_PVID_STATE: ++ be_async_grp5_pvid_state_process(adapter, ++ (struct be_async_event_grp5_pvid_state *)evt); ++ break; ++ case GRP5_TYPE_PRIO_TC_MAP: ++ memcpy(adapter->prio_tc_map, evt, MAX_TX_QS); ++ break; ++ default: ++ printk(KERN_WARNING "Unknown grp5 event!\n"); ++ break; ++ } + } + + static inline bool is_link_state_evt(u32 trailer) +@@ -92,6 +216,13 @@ static inline bool is_link_state_evt(u32 trailer) + ASYNC_EVENT_CODE_LINK_STATE); + } + ++static inline bool is_grp5_evt(u32 trailer) ++{ ++ return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & ++ ASYNC_TRAILER_EVENT_CODE_MASK) == ++ ASYNC_EVENT_CODE_GRP_5); ++} ++ + static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) + { + struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; +@@ -104,46 +235,67 @@ static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) + return NULL; + } + +-int be_process_mcc(struct be_adapter *adapter) ++void be_async_mcc_enable(struct be_adapter *adapter) ++{ ++ spin_lock_bh(&adapter->mcc_cq_lock); ++ ++ be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0); ++ adapter->mcc_obj.rearm_cq = true; ++ ++ spin_unlock_bh(&adapter->mcc_cq_lock); ++} ++ ++void be_async_mcc_disable(struct be_adapter *adapter) ++{ ++ adapter->mcc_obj.rearm_cq = false; ++} ++ ++int be_process_mcc(struct be_adapter *adapter, int *status) + { + struct be_mcc_compl *compl; +- int num = 0, status = 0; ++ int num = 0; ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + + spin_lock_bh(&adapter->mcc_cq_lock); + while ((compl = be_mcc_compl_get(adapter))) { + if (compl->flags & CQE_FLAGS_ASYNC_MASK) { + /* Interpret flags as an async trailer */ +- BUG_ON(!is_link_state_evt(compl->flags)); +- +- /* Interpret compl as a async link evt */ +- be_async_link_state_process(adapter, ++ if (is_link_state_evt(compl->flags)) ++ be_async_link_state_process(adapter, + (struct be_async_event_link_state *) compl); ++ else if (is_grp5_evt(compl->flags)) ++ be_async_grp5_evt_process(adapter, ++ compl->flags, compl); ++ + } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { +- status = be_mcc_compl_process(adapter, compl); +- atomic_dec(&adapter->mcc_obj.q.used); ++ *status = be_mcc_compl_process(adapter, compl); ++ atomic_dec(&mcc_obj->q.used); + } + be_mcc_compl_use(compl); + num++; + } + +- if (num) +- be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num); +- + spin_unlock_bh(&adapter->mcc_cq_lock); +- return status; ++ return num; + } + + /* Wait till no more pending mcc requests are present */ + static int be_mcc_wait_compl(struct be_adapter *adapter) + { + #define mcc_timeout 120000 /* 12s timeout */ +- int i, status; ++ int i, num, status = 0; ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; ++ ++ if (adapter->eeh_err) ++ return -EIO; ++ + for (i = 0; i < mcc_timeout; i++) { +- status = be_process_mcc(adapter); +- if (status) +- return status; ++ num = be_process_mcc(adapter, &status); ++ if (num) ++ be_cq_notify(adapter, mcc_obj->cq.id, ++ mcc_obj->rearm_cq, num); + +- if (atomic_read(&adapter->mcc_obj.q.used) == 0) ++ if (atomic_read(&mcc_obj->q.used) == 0) + break; + udelay(100); + } +@@ -151,7 +303,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) + dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); + return -1; + } +- return 0; ++ return status; + } + + /* Notify MCC requests and wait for completion */ +@@ -163,23 +315,34 @@ static int be_mcc_notify_wait(struct be_adapter *adapter) + + static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) + { +- int cnt = 0, wait = 5; ++ int msecs = 0; + u32 ready; + ++ if (adapter->eeh_err) { ++ dev_err(&adapter->pdev->dev, "Error detected in card.Cannot issue commands\n"); ++ return -EIO; ++ } + do { +- ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK; ++ ready = ioread32(db); ++ if (ready == 0xffffffff) { ++ dev_err(&adapter->pdev->dev, ++ "pci slot disconnected\n"); ++ return -1; ++ } ++ ++ ready &= MPU_MAILBOX_DB_RDY_MASK; + if (ready) + break; + +- if (cnt > 4000000) { ++ if (msecs > 4000) { + dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); ++ be_detect_dump_ue(adapter); + return -1; + } + +- if (cnt > 50) +- wait = 200; +- cnt += wait; +- udelay(wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(msecs_to_jiffies(1)); ++ msecs++; + } while (true); + + return 0; +@@ -198,6 +361,11 @@ static int be_mbox_notify_wait(struct be_adapter *adapter) + struct be_mcc_mailbox *mbox = mbox_mem->va; + struct be_mcc_compl *compl = &mbox->compl; + ++ /* wait for ready to be set */ ++ status = be_mbox_db_ready_wait(adapter, db); ++ if (status != 0) ++ return status; ++ + val |= MPU_MAILBOX_DB_HI_MASK; + /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ + val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; +@@ -232,7 +400,12 @@ static int be_mbox_notify_wait(struct be_adapter *adapter) + + static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) + { +- u32 sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET); ++ u32 sem; ++ ++ if (lancer_chip(adapter)) ++ sem = ioread32(adapter->db + MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET); ++ else ++ sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET); + + *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK; + if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK) +@@ -245,30 +418,29 @@ int be_cmd_POST(struct be_adapter *adapter) + { + u16 stage; + int status, timeout = 0; ++ struct device *dev = &adapter->pdev->dev; + + do { + status = be_POST_stage_get(adapter, &stage); + if (status) { +- dev_err(&adapter->pdev->dev, "POST error; stage=0x%x\n", +- stage); ++ dev_err(dev, "POST error; stage=0x%x\n", stage); + return -1; + } else if (stage != POST_STAGE_ARMFW_RDY) { + set_current_state(TASK_INTERRUPTIBLE); +- schedule_timeout(2 * HZ); ++ if (schedule_timeout(2 * HZ)) { ++ dev_err(dev, "POST cmd aborted\n"); ++ return -EINTR; ++ } + timeout += 2; + } else { + return 0; + } +- } while (timeout < 20); ++ } while (timeout < 40); + +- dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage); ++ dev_err(dev, "POST timeout; stage=0x%x\n", stage); + return -1; + } + +-static inline void *embedded_payload(struct be_mcc_wrb *wrb) +-{ +- return wrb->payload.embedded_payload; +-} + + static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) + { +@@ -277,7 +449,7 @@ static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) + + /* Don't touch the hdr after it's prepared */ + static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, +- bool embedded, u8 sge_cnt) ++ bool embedded, u8 sge_cnt, u32 opcode) + { + if (embedded) + wrb->embedded |= MCC_WRB_EMBEDDED_MASK; +@@ -285,7 +457,8 @@ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, + wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << + MCC_WRB_SGE_CNT_SHIFT; + wrb->payload_length = payload_len; +- be_dws_cpu_to_le(wrb, 20); ++ wrb->tag0 = opcode; ++ be_dws_cpu_to_le(wrb, 8); + } + + /* Don't touch the hdr after it's prepared */ +@@ -295,6 +468,7 @@ static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, + req_hdr->opcode = opcode; + req_hdr->subsystem = subsystem; + req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); ++ req_hdr->version = 0; + } + + static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, +@@ -349,7 +523,11 @@ static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter) + struct be_queue_info *mccq = &adapter->mcc_obj.q; + struct be_mcc_wrb *wrb; + +- BUG_ON(atomic_read(&mccq->used) >= mccq->len); ++ if (atomic_read(&mccq->used) >= mccq->len) { ++ dev_err(&adapter->pdev->dev, "Out of MCCQ wrbs\n"); ++ return NULL; ++ } ++ + wrb = queue_head_node(mccq); + queue_head_inc(mccq); + atomic_inc(&mccq->used); +@@ -357,6 +535,59 @@ static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter) + return wrb; + } + ++/* Tell fw we're about to start firing cmds by writing a ++ * special pattern across the wrb hdr; uses mbox ++ */ ++int be_cmd_fw_init(struct be_adapter *adapter) ++{ ++ u8 *wrb; ++ int status; ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = (u8 *)wrb_from_mbox(adapter); ++ *wrb++ = 0xFF; ++ *wrb++ = 0x12; ++ *wrb++ = 0x34; ++ *wrb++ = 0xFF; ++ *wrb++ = 0xFF; ++ *wrb++ = 0x56; ++ *wrb++ = 0x78; ++ *wrb = 0xFF; ++ ++ status = be_mbox_notify_wait(adapter); ++ ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} ++ ++/* Tell fw we're done with firing cmds by writing a ++ * special pattern across the wrb hdr; uses mbox ++ */ ++int be_cmd_fw_clean(struct be_adapter *adapter) ++{ ++ u8 *wrb; ++ int status; ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = (u8 *)wrb_from_mbox(adapter); ++ *wrb++ = 0xFF; ++ *wrb++ = 0xAA; ++ *wrb++ = 0xBB; ++ *wrb++ = 0xFF; ++ *wrb++ = 0xFF; ++ *wrb++ = 0xCC; ++ *wrb++ = 0xDD; ++ *wrb = 0xFF; ++ ++ status = be_mbox_notify_wait(adapter); ++ ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} + int be_cmd_eq_create(struct be_adapter *adapter, + struct be_queue_info *eq, int eq_delay) + { +@@ -365,20 +596,19 @@ int be_cmd_eq_create(struct be_adapter *adapter, + struct be_dma_mem *q_mem = &eq->dma_mem; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_COMMON_EQ_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_EQ_CREATE, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + +- AMAP_SET_BITS(struct amap_eq_context, func, req->context, +- be_pci_func(adapter)); + AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); + /* 4byte eqe*/ + AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); +@@ -397,7 +627,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, + eq->created = true; + } + +- spin_unlock(&adapter->mbox_lock); ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + +@@ -409,12 +639,14 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, + struct be_cmd_req_mac_query *req; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_MAC_QUERY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req)); +@@ -433,13 +665,13 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, + memcpy(mac_addr, resp->mac.addr, ETH_ALEN); + } + +- spin_unlock(&adapter->mbox_lock); ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + + /* Uses synchronous MCCQ */ + int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, +- u32 if_id, u32 *pmac_id) ++ u32 if_id, u32 *pmac_id, u32 domain) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_pmac_add *req; +@@ -448,13 +680,19 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_PMAC_ADD); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req)); + ++ req->hdr.domain = domain; + req->if_id = cpu_to_le32(if_id); + memcpy(req->mac_address, mac_addr, ETH_ALEN); + +@@ -464,12 +702,13 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, + *pmac_id = le32_to_cpu(resp->pmac_id); + } + ++err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } + + /* Uses synchronous MCCQ */ +-int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) ++int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_pmac_del *req; +@@ -478,20 +717,26 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_PMAC_DEL); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req)); + ++ req->hdr.domain = dom; + req->if_id = cpu_to_le32(if_id); + req->pmac_id = cpu_to_le32(pmac_id); + + status = be_mcc_notify_wait(adapter); + ++err: + spin_unlock_bh(&adapter->mcc_lock); +- + return status; + } + +@@ -506,29 +751,51 @@ int be_cmd_cq_create(struct be_adapter *adapter, + void *ctxt; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_CQ_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_CQ_CREATE, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + +- AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm); +- AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay); +- AMAP_SET_BITS(struct amap_cq_context, count, ctxt, +- __ilog2_u32(cq->len/256)); +- AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1); +- AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts); +- AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); +- AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); +- AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); +- AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter)); ++ if (lancer_chip(adapter)) { ++ req->hdr.version = 2; ++ req->page_size = 1; /* 1 for 4K */ ++ AMAP_SET_BITS(struct amap_cq_context_lancer, coalescwm, ctxt, ++ coalesce_wm); ++ AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt, ++ no_delay); ++ AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt, ++ __ilog2_u32(cq->len/256)); ++ AMAP_SET_BITS(struct amap_cq_context_lancer, valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_cq_context_lancer, eventable, ++ ctxt, 1); ++ AMAP_SET_BITS(struct amap_cq_context_lancer, eqid, ++ ctxt, eq->id); ++ AMAP_SET_BITS(struct amap_cq_context_lancer, armed, ctxt, 1); ++ } else { ++ AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt, ++ coalesce_wm); ++ AMAP_SET_BITS(struct amap_cq_context_be, nodelay, ++ ctxt, no_delay); ++ AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt, ++ __ilog2_u32(cq->len/256)); ++ AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_cq_context_be, solevent, ++ ctxt, sol_evts); ++ AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1); ++ AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id); ++ AMAP_SET_BITS(struct amap_cq_context_be, armed, ctxt, 1); ++ } ++ + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); +@@ -540,8 +807,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, + cq->created = true; + } + +- spin_unlock(&adapter->mbox_lock); +- ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + +@@ -553,7 +819,68 @@ static u32 be_encoded_q_len(int q_len) + return len_encoded; + } + +-int be_cmd_mccq_create(struct be_adapter *adapter, ++int be_cmd_mccq_ext_create(struct be_adapter *adapter, ++ struct be_queue_info *mccq, ++ struct be_queue_info *cq) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_mcc_ext_create *req; ++ struct be_dma_mem *q_mem = &mccq->dma_mem; ++ void *ctxt; ++ int status; ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = wrb_from_mbox(adapter); ++ req = embedded_payload(wrb); ++ ctxt = &req->context; ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_MCC_CREATE_EXT); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req)); ++ ++ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); ++ if (lancer_chip(adapter)) { ++ req->hdr.version = 1; ++ req->cq_id = cpu_to_le16(cq->id); ++ ++ AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt, ++ be_encoded_q_len(mccq->len)); ++ AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id, ++ ctxt, cq->id); ++ AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid, ++ ctxt, 1); ++ ++ } else { ++ AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, ++ be_encoded_q_len(mccq->len)); ++ AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); ++ } ++ ++ /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ ++ req->async_event_bitmap[0] |= cpu_to_le32(0x00000022); ++ ++ be_dws_cpu_to_le(ctxt, sizeof(req->context)); ++ ++ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); ++ ++ status = be_mbox_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); ++ mccq->id = le16_to_cpu(resp->id); ++ mccq->created = true; ++ } ++ ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} ++ ++int be_cmd_mccq_org_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq) + { +@@ -563,24 +890,25 @@ int be_cmd_mccq_create(struct be_adapter *adapter, + void *ctxt; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_MCC_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MCC_CREATE, sizeof(*req)); + +- req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); ++ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + +- AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter)); +- AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); +- AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, +- be_encoded_q_len(mccq->len)); +- AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id); ++ AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, ++ be_encoded_q_len(mccq->len)); ++ AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + +@@ -592,75 +920,93 @@ int be_cmd_mccq_create(struct be_adapter *adapter, + mccq->id = le16_to_cpu(resp->id); + mccq->created = true; + } +- spin_unlock(&adapter->mbox_lock); + ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + +-int be_cmd_txq_create(struct be_adapter *adapter, +- struct be_queue_info *txq, ++int be_cmd_mccq_create(struct be_adapter *adapter, ++ struct be_queue_info *mccq, + struct be_queue_info *cq) + { ++ int status; ++ ++ status = be_cmd_mccq_ext_create(adapter, mccq, cq); ++ if (status && !lancer_chip(adapter)) { ++ dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " ++ "or newer to avoid conflicting priorities between NIC " ++ "and FCoE traffic"); ++ status = be_cmd_mccq_org_create(adapter, mccq, cq); ++ } ++ return status; ++} ++ ++int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq, ++ struct be_queue_info *cq, u8 *tc_id) ++{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_eth_tx_create *req; + struct be_dma_mem *q_mem = &txq->dma_mem; +- void *ctxt; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); +- ctxt = &req->context; +- +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_TX_CREATE); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE, + sizeof(*req)); + +- req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); ++ if (adapter->flags & BE_FLAGS_DCBX || lancer_chip(adapter)) { ++ req->hdr.version = 1; ++ req->if_id = cpu_to_le16(adapter->if_handle); ++ } ++ if (adapter->flags & BE_FLAGS_DCBX) ++ req->type = cpu_to_le16(ETX_QUEUE_TYPE_PRIORITY); ++ else ++ req->type = cpu_to_le16(ETX_QUEUE_TYPE_STANDARD); + req->ulp_num = BE_ULP1_NUM; +- req->type = BE_ETH_TX_RING_TYPE_STANDARD; +- +- AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, +- be_encoded_q_len(txq->len)); +- AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, +- be_pci_func(adapter)); +- AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); +- AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); +- +- be_dws_cpu_to_le(ctxt, sizeof(req->context)); +- ++ req->cq_id = cpu_to_le16(cq->id); ++ req->queue_size = be_encoded_q_len(txq->len); ++ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); + txq->id = le16_to_cpu(resp->cid); ++ if (adapter->flags & BE_FLAGS_DCBX) ++ *tc_id = resp->tc_id; + txq->created = true; + } + +- spin_unlock(&adapter->mbox_lock); +- ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + +-/* Uses mbox */ ++/* Uses MCC */ + int be_cmd_rxq_create(struct be_adapter *adapter, + struct be_queue_info *rxq, u16 cq_id, u16 frag_size, +- u16 max_frame_size, u32 if_id, u32 rss) ++ u16 max_frame_size, u32 if_id, u32 rss, u8 *rss_id) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_eth_rx_create *req; + struct be_dma_mem *q_mem = &rxq->dma_mem; + int status; + +- spin_lock(&adapter->mbox_lock); ++ spin_lock_bh(&adapter->mcc_lock); + +- wrb = wrb_from_mbox(adapter); ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_ETH_RX_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE, + sizeof(*req)); +@@ -673,15 +1019,16 @@ int be_cmd_rxq_create(struct be_adapter *adapter, + req->max_frame_size = cpu_to_le16(max_frame_size); + req->rss_queue = cpu_to_le32(rss); + +- status = be_mbox_notify_wait(adapter); ++ status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); + rxq->id = le16_to_cpu(resp->id); + rxq->created = true; ++ *rss_id = resp->rss_id; + } + +- spin_unlock(&adapter->mbox_lock); +- ++err: ++ spin_unlock_bh(&adapter->mcc_lock); + return status; + } + +@@ -696,13 +1043,12 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + u8 subsys = 0, opcode = 0; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +- + switch (queue_type) { + case QTYPE_EQ: + subsys = CMD_SUBSYSTEM_COMMON; +@@ -727,13 +1073,47 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + default: + BUG(); + } ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, opcode); ++ + be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); + req->id = cpu_to_le16(q->id); + + status = be_mbox_notify_wait(adapter); ++ if (!status) ++ q->created = false; + +- spin_unlock(&adapter->mbox_lock); ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} + ++/* Uses MCC */ ++int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_q_destroy *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_RX_DESTROY); ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_DESTROY, ++ sizeof(*req)); ++ req->id = cpu_to_le16(q->id); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) ++ q->created = false; ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); + return status; + } + +@@ -741,22 +1121,26 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + * Uses mbox + */ + int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, +- u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id) ++ u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id, ++ u32 domain) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_if_create *req; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_INTERFACE_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req)); + ++ req->hdr.domain = domain; + req->capability_flags = cpu_to_le32(cap_flags); + req->enable_flags = cpu_to_le32(en_flags); + req->pmac_invalid = pmac_invalid; +@@ -771,33 +1155,35 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, + *pmac_id = le32_to_cpu(resp->pmac_id); + } + +- spin_unlock(&adapter->mbox_lock); ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + + /* Uses mbox */ +-int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) ++int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_if_destroy *req; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_INTERFACE_DESTROY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); + ++ req->hdr.domain = domain; + req->interface_id = cpu_to_le32(interface_id); + + status = be_mbox_notify_wait(adapter); + +- spin_unlock(&adapter->mbox_lock); +- ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + +@@ -808,33 +1194,48 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) + int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) + { + struct be_mcc_wrb *wrb; +- struct be_cmd_req_get_stats *req; ++ struct be_cmd_req_hdr *hdr; + struct be_sge *sge; ++ int status = 0; ++ ++ if (MODULO(adapter->work_counter, be_get_temp_freq) == 0) ++ be_cmd_get_die_temperature(adapter); + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); +- req = nonemb_cmd->va; ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ hdr = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); +- wrb->tag0 = OPCODE_ETH_GET_STATISTICS; ++ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, ++ OPCODE_ETH_GET_STATISTICS); + +- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, +- OPCODE_ETH_GET_STATISTICS, sizeof(*req)); ++ be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH, ++ OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size); ++ ++ if (adapter->generation == BE_GEN3) ++ hdr->version = 1; ++ ++ wrb->tag1 = CMD_SUBSYSTEM_ETH; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + be_mcc_notify(adapter); ++ adapter->stats_cmd_sent = true; + ++err: + spin_unlock_bh(&adapter->mcc_lock); +- return 0; ++ return status; + } + + /* Uses synchronous mcc */ + int be_cmd_link_status_query(struct be_adapter *adapter, +- bool *link_up) ++ int *link_status, u8 *mac_speed, u16 *link_speed, u32 dom) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_link_status *req; +@@ -843,50 +1244,216 @@ int be_cmd_link_status_query(struct be_adapter *adapter, + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- *link_up = false; ++ *link_status = LINK_DOWN; + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_LINK_STATUS_QUERY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); + ++ req->hdr.domain = dom; ++ + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_link_status *resp = embedded_payload(wrb); +- if (resp->mac_speed != PHY_LINK_SPEED_ZERO) +- *link_up = true; ++ if (resp->mac_speed != PHY_LINK_SPEED_ZERO) { ++ *link_status = LINK_UP; ++ *link_speed = le16_to_cpu(resp->link_speed); ++ *mac_speed = resp->mac_speed; ++ } + } + ++err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } + +-/* Uses Mbox */ +-int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) ++/* Uses synchronous mcc */ ++int be_cmd_get_die_temperature(struct be_adapter *adapter) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_cntl_addnl_attribs *req; ++ u16 mccq_index; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ mccq_index = adapter->mcc_obj.q.head; ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req)); ++ ++ wrb->tag1 = mccq_index; ++ ++ be_mcc_notify(adapter); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++ ++/* Uses synchronous mcc */ ++int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_fat *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_MANAGE_FAT); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_MANAGE_FAT, sizeof(*req)); ++ req->fat_operation = cpu_to_le32(QUERY_FAT); ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); ++ if (log_size && resp->log_size) ++ *log_size = le32_to_cpu(resp->log_size) - ++ sizeof(u32); ++ } ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) ++{ ++ struct be_dma_mem get_fat_cmd; ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_fat *req; ++ struct be_sge *sge; ++ u32 offset = 0, total_size, buf_size, ++ log_offset = sizeof(u32), payload_len; ++ int status; ++ ++ if (buf_len == 0) ++ return; ++ ++ total_size = buf_len; ++ ++ get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024; ++ get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, ++ get_fat_cmd.size, ++ &get_fat_cmd.dma); ++ if (!get_fat_cmd.va) { ++ status = -ENOMEM; ++ dev_err(&adapter->pdev->dev, ++ "Memory allocation failure while retrieving FAT data\n"); ++ return; ++ } ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ while (total_size) { ++ buf_size = min(total_size, (u32)60*1024); ++ total_size -= buf_size; ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = get_fat_cmd.va; ++ sge = nonembedded_sgl(wrb); ++ ++ payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; ++ be_wrb_hdr_prepare(wrb, payload_len, false, 1, ++ OPCODE_COMMON_MANAGE_FAT); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_MANAGE_FAT, payload_len); ++ ++ sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma)); ++ sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(get_fat_cmd.size); ++ ++ req->fat_operation = cpu_to_le32(RETRIEVE_FAT); ++ req->read_log_offset = cpu_to_le32(log_offset); ++ req->read_log_length = cpu_to_le32(buf_size); ++ req->data_buffer_size = cpu_to_le32(buf_size); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; ++ memcpy(buf + offset, ++ resp->data_buffer, ++ le32_to_cpu(resp->read_log_length)); ++ } else { ++ dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); ++ goto err; ++ } ++ offset += buf_size; ++ log_offset += buf_size; ++ } ++err: ++ pci_free_consistent(adapter->pdev, get_fat_cmd.size, ++ get_fat_cmd.va, ++ get_fat_cmd.dma); ++ spin_unlock_bh(&adapter->mcc_lock); ++} ++ ++/* Uses synchronous mcc */ ++int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, ++ char *fw_on_flash) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fw_version *req; + int status; + +- spin_lock(&adapter->mbox_lock); ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + +- wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_FW_VERSION); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); + +- status = be_mbox_notify_wait(adapter); ++ status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); +- strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); ++ strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN-1); ++ if (fw_on_flash) ++ strncpy(fw_on_flash, resp->fw_on_flash_version_string, ++ FW_VER_LEN-1); + } +- +- spin_unlock(&adapter->mbox_lock); ++err: ++ spin_unlock_bh(&adapter->mcc_lock); + return status; + } + +@@ -897,13 +1464,19 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_modify_eq_delay *req; ++ int status = 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_MODIFY_EQ_DELAY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); +@@ -915,8 +1488,9 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) + + be_mcc_notify(adapter); + ++err: + spin_unlock_bh(&adapter->mcc_lock); +- return 0; ++ return status; + } + + /* Uses sycnhronous mcc */ +@@ -930,9 +1504,14 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_VLAN_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req)); +@@ -948,79 +1527,63 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, + + status = be_mcc_notify_wait(adapter); + ++err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } + +-/* Uses MCC for this command as it may be called in BH context +- * Uses synchronous mcc +- */ +-int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) ++int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) + { + struct be_mcc_wrb *wrb; +- struct be_cmd_req_promiscuous_config *req; ++ struct be_dma_mem *mem = &adapter->rx_filter; ++ struct be_cmd_req_rx_filter *req = mem->va; ++ struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); +- req = embedded_payload(wrb); +- +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +- +- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, +- OPCODE_ETH_PROMISCUOUS, sizeof(*req)); +- +- if (port_num) +- req->port1_promiscuous = en; +- else +- req->port0_promiscuous = en; +- +- status = be_mcc_notify_wait(adapter); +- +- spin_unlock_bh(&adapter->mcc_lock); +- return status; +-} +- +-/* +- * Uses MCC for this command as it may be called in BH context +- * (mc == NULL) => multicast promiscous +- */ +-int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, +- struct dev_mc_list *mc_list, u32 mc_count) +-{ +-#define BE_MAX_MC 32 /* set mcast promisc if > 32 */ +- struct be_mcc_wrb *wrb; +- struct be_cmd_req_mcast_mac_config *req; +- +- spin_lock_bh(&adapter->mcc_lock); +- +- wrb = wrb_from_mccq(adapter); +- req = embedded_payload(wrb); +- +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +- ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ sge = nonembedded_sgl(wrb); ++ sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma)); ++ sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(mem->size); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, ++ OPCODE_COMMON_NTWK_RX_FILTER); ++ ++ memset(req, 0, sizeof(*req)); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +- OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req)); ++ OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req)); + +- req->interface_id = if_id; +- if (mc_list && mc_count <= BE_MAX_MC) { +- int i; +- struct dev_mc_list *mc; +- +- req->num_mac = cpu_to_le16(mc_count); +- +- for (mc = mc_list, i = 0; mc; mc = mc->next, i++) +- memcpy(req->mac[i].byte, mc->dmi_addr, ETH_ALEN); ++ req->if_id = cpu_to_le32(adapter->if_handle); ++ if (flags & IFF_PROMISC) { ++ req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | ++ BE_IF_FLAGS_VLAN_PROMISCUOUS); ++ if (value == ON) ++ req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | ++ BE_IF_FLAGS_VLAN_PROMISCUOUS); ++ } else if (flags & IFF_ALLMULTI) { ++ req->if_flags_mask = req->if_flags = ++ cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); + } else { +- req->promiscuous = 1; +- } ++ struct netdev_hw_addr *ha; ++ int i = 0; + +- be_mcc_notify_wait(adapter); ++ req->if_flags_mask = req->if_flags = ++ cpu_to_le32(BE_IF_FLAGS_MULTICAST); ++ req->mcast_num = cpu_to_le16(netdev_mc_count(adapter->netdev)); ++ netdev_for_each_mc_addr(ha, adapter->netdev) ++ memcpy(req->mcast_mac[i++].byte, ha->DMI_ADDR, ++ ETH_ALEN); ++ } ++ status = be_mcc_notify_wait(adapter); + ++err: + spin_unlock_bh(&adapter->mcc_lock); +- +- return 0; ++ return status; + } + + /* Uses synchrounous mcc */ +@@ -1033,9 +1596,14 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_SET_FLOW_CONTROL); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req)); +@@ -1045,6 +1613,7 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) + + status = be_mcc_notify_wait(adapter); + ++err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } +@@ -1059,9 +1628,14 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_FLOW_CONTROL); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); +@@ -1074,23 +1648,27 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) + *rx_fc = le16_to_cpu(resp->rx_flow_control); + } + ++err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } + + /* Uses mbox */ +-int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap) ++int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, ++ u32 *mode, u32 *function_caps) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_query_fw_cfg *req; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_QUERY_FIRMWARE_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); +@@ -1099,10 +1677,11 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap) + if (!status) { + struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); + *port_num = le32_to_cpu(resp->phys_port); +- *cap = le32_to_cpu(resp->function_cap); ++ *mode = le32_to_cpu(resp->function_mode); ++ *function_caps = le32_to_cpu(resp->function_caps); + } + +- spin_unlock(&adapter->mbox_lock); ++ mutex_unlock(&adapter->mbox_lock); + return status; + } + +@@ -1113,19 +1692,161 @@ int be_cmd_reset_function(struct be_adapter *adapter) + struct be_cmd_req_hdr *req; + int status; + +- spin_lock(&adapter->mbox_lock); ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + +- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_FUNCTION_RESET); + + be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); + + status = be_mbox_notify_wait(adapter); + +- spin_unlock(&adapter->mbox_lock); ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} ++ ++int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_rss_config *req; ++ u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF, ++ 0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF}; ++ int status; ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = wrb_from_mbox(adapter); ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_ETH_RSS_CONFIG); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, ++ OPCODE_ETH_RSS_CONFIG, sizeof(*req)); ++ ++ req->if_id = cpu_to_le32(adapter->if_handle); ++ req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4); ++ req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1); ++ memcpy(req->cpu_table, rsstable, table_size); ++ memcpy(req->hash, myhash, sizeof(myhash)); ++ be_dws_cpu_to_le(req->hash, sizeof(req->hash)); ++ ++ status = be_mbox_notify_wait(adapter); ++ ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} ++ ++/* Uses sync mcc */ ++int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, ++ u8 bcn, u8 sts, u8 state) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_enable_disable_beacon *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_ENABLE_DISABLE_BEACON); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req)); ++ ++ req->port_num = port_num; ++ req->beacon_state = state; ++ req->beacon_duration = bcn; ++ req->status_duration = sts; ++ ++ status = be_mcc_notify_wait(adapter); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Uses sync mcc */ ++int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_beacon_state *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_BEACON_STATE); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req)); ++ ++ req->port_num = port_num; ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_beacon_state *resp = ++ embedded_payload(wrb); ++ *state = resp->beacon_state; ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Uses sync mcc */ ++int be_cmd_read_port_type(struct be_adapter *adapter, u32 port, ++ u8 *connector) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_port_type *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(struct be_cmd_resp_port_type), true, 0, ++ OPCODE_COMMON_READ_TRANSRECV_DATA); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_READ_TRANSRECV_DATA, sizeof(*req)); ++ ++ req->port = cpu_to_le32(port); ++ req->page_num = cpu_to_le32(TR_PAGE_A0); ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_port_type *resp = embedded_payload(wrb); ++ *connector = resp->data.connector; ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); + return status; + } + +@@ -1133,16 +1854,24 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 flash_type, u32 flash_opcode, u32 buf_size) + { + struct be_mcc_wrb *wrb; +- struct be_cmd_write_flashrom *req = cmd->va; ++ struct be_cmd_write_flashrom *req; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); ++ adapter->flash_status = 0; + + wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err_unlock; ++ } ++ req = cmd->va; + sge = nonembedded_sgl(wrb); + +- be_wrb_hdr_prepare(wrb, cmd->size, false, 1); ++ be_wrb_hdr_prepare(wrb, cmd->size, false, 1, ++ OPCODE_COMMON_WRITE_FLASHROM); ++ wrb->tag1 = CMD_SUBSYSTEM_COMMON; + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_FLASHROM, cmd->size); +@@ -1154,8 +1883,852 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, + req->params.op_code = cpu_to_le32(flash_opcode); + req->params.data_buf_size = cpu_to_le32(buf_size); + ++ be_mcc_notify(adapter); ++ spin_unlock_bh(&adapter->mcc_lock); ++ ++ if (!wait_for_completion_timeout(&adapter->flash_compl, ++ msecs_to_jiffies(40000))) ++ status = -1; ++ else ++ status = adapter->flash_status; ++ ++ return status; ++ ++err_unlock: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, ++ int offset) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_write_flashrom *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req)+4, true, 0, ++ OPCODE_COMMON_READ_FLASHROM); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4); ++ ++ req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT); ++ req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); ++ req->params.offset = cpu_to_le32(offset); ++ req->params.data_buf_size = cpu_to_le32(0x4); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) ++ memcpy(flashed_crc, req->params.data_buf, 4); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, ++ struct be_dma_mem *nonemb_cmd) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_acpi_wol_magic_config *req; ++ struct be_sge *sge; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = nonemb_cmd->va; ++ sge = nonembedded_sgl(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, ++ OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, ++ OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req)); ++ memcpy(req->magic_mac, mac, ETH_ALEN); ++ ++ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); ++ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(nonemb_cmd->size); ++ ++ status = be_mcc_notify_wait(adapter); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, ++ u8 loopback_type, u8 enable) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_lmode *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_LOWLEVEL_SET_LOOPBACK_MODE); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, ++ OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, ++ sizeof(*req)); ++ ++ req->src_port = port_num; ++ req->dest_port = port_num; ++ req->loopback_type = loopback_type; ++ req->loopback_state = enable; ++ ++ status = be_mcc_notify_wait(adapter); ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, ++ u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_loopback_test *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_LOWLEVEL_LOOPBACK_TEST); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, ++ OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req)); ++ req->hdr.timeout = cpu_to_le32(4); ++ ++ req->pattern = cpu_to_le64(pattern); ++ req->src_port = cpu_to_le32(port_num); ++ req->dest_port = cpu_to_le32(port_num); ++ req->pkt_size = cpu_to_le32(pkt_size); ++ req->num_pkts = cpu_to_le32(num_pkts); ++ req->loopback_type = cpu_to_le32(loopback_type); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_loopback_test *resp = embedded_payload(wrb); ++ status = le32_to_cpu(resp->status); ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, ++ u32 byte_cnt, struct be_dma_mem *cmd) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_ddrdma_test *req; ++ struct be_sge *sge; ++ int status; ++ int i, j = 0; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = cmd->va; ++ sge = nonembedded_sgl(wrb); ++ be_wrb_hdr_prepare(wrb, cmd->size, false, 1, ++ OPCODE_LOWLEVEL_HOST_DDR_DMA); ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, ++ OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size); ++ ++ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); ++ sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(cmd->size); ++ ++ req->pattern = cpu_to_le64(pattern); ++ req->byte_count = cpu_to_le32(byte_cnt); ++ for (i = 0; i < byte_cnt; i++) { ++ req->snd_buff[i] = (u8)(pattern >> (j*8)); ++ j++; ++ if (j > 7) ++ j = 0; ++ } ++ ++ status = be_mcc_notify_wait(adapter); ++ ++ if (!status) { ++ struct be_cmd_resp_ddrdma_test *resp; ++ resp = cmd->va; ++ if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) || ++ resp->snd_err) { ++ status = -1; ++ } ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_get_seeprom_data(struct be_adapter *adapter, ++ struct be_dma_mem *nonemb_cmd) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_seeprom_read *req; ++ struct be_sge *sge; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ req = nonemb_cmd->va; ++ sge = nonembedded_sgl(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, ++ OPCODE_COMMON_SEEPROM_READ); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SEEPROM_READ, sizeof(*req)); ++ ++ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); ++ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(nonemb_cmd->size); ++ ++ status = be_mcc_notify_wait(adapter); ++ ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_get_phy_info(struct be_adapter *adapter, ++ struct be_phy_info *phy_info) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_phy_info *req; ++ struct be_sge *sge; ++ struct be_dma_mem cmd; ++ struct be_phy_info *resp_phy_info; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ cmd.size = sizeof(struct be_cmd_req_get_phy_info); ++ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, ++ &cmd.dma); ++ if (!cmd.va) { ++ dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); ++ status = -ENOMEM; ++ goto err; ++ } ++ ++ req = cmd.va; ++ sge = nonembedded_sgl(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, ++ OPCODE_COMMON_GET_PHY_DETAILS); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_PHY_DETAILS, ++ sizeof(*req)); ++ ++ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd.dma)); ++ sge->pa_lo = cpu_to_le32(cmd.dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(cmd.size); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ resp_phy_info = cmd.va + sizeof(struct be_cmd_req_hdr); ++ phy_info->phy_type = le16_to_cpu(resp_phy_info->phy_type); ++ phy_info->interface_type = ++ le16_to_cpu(resp_phy_info->interface_type); ++ phy_info->auto_speeds_supported = ++ le16_to_cpu(resp_phy_info->auto_speeds_supported); ++ phy_info->fixed_speeds_supported = ++ le16_to_cpu(resp_phy_info->fixed_speeds_supported); ++ phy_info->misc_params = ++ le32_to_cpu(resp_phy_info->misc_params); ++ } ++ pci_free_consistent(adapter->pdev, cmd.size, ++ cmd.va, cmd.dma); ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_qos *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_SET_QOS); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SET_QOS, sizeof(*req)); ++ ++ req->hdr.domain = domain; ++ req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC); ++ req->max_bps_nic = cpu_to_le32(bps); ++ ++ status = be_mcc_notify_wait(adapter); ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_get_cntl_attributes(struct be_adapter *adapter) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_cntl_attribs *req; ++ struct be_cmd_resp_cntl_attribs *resp; ++ struct be_sge *sge; ++ int status; ++ int payload_len = max(sizeof(*req), sizeof(*resp)); ++ struct mgmt_controller_attrib *attribs; ++ struct be_dma_mem attribs_cmd; ++ ++ memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); ++ attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); ++ attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size, ++ &attribs_cmd.dma); ++ if (!attribs_cmd.va) { ++ dev_err(&adapter->pdev->dev, ++ "Memory allocation failure\n"); ++ return -ENOMEM; ++ } ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = wrb_from_mbox(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = attribs_cmd.va; ++ sge = nonembedded_sgl(wrb); ++ ++ be_wrb_hdr_prepare(wrb, payload_len, false, 1, ++ OPCODE_COMMON_GET_CNTL_ATTRIBUTES); ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_CNTL_ATTRIBUTES, payload_len); ++ sge->pa_hi = cpu_to_le32(upper_32_bits(attribs_cmd.dma)); ++ sge->pa_lo = cpu_to_le32(attribs_cmd.dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(attribs_cmd.size); ++ ++ status = be_mbox_notify_wait(adapter); ++ if (!status) { ++ attribs = (struct mgmt_controller_attrib *)(attribs_cmd.va + ++ sizeof(struct be_cmd_resp_hdr)); ++ adapter->hba_port_num = attribs->hba_attribs.phy_port; ++ strncpy(adapter->model_number, ++ attribs->hba_attribs.controller_model_number, 31); ++ } ++ ++err: ++ mutex_unlock(&adapter->mbox_lock); ++ pci_free_consistent(adapter->pdev, attribs_cmd.size, attribs_cmd.va, ++ attribs_cmd.dma); ++ return status; ++} ++ ++/* Uses mbox */ ++int be_cmd_req_native_mode(struct be_adapter *adapter) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_func_cap *req; ++ int status; ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = wrb_from_mbox(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, sizeof(*req)); ++ ++ req->valid_cap_flags = cpu_to_le32(CAPABILITY_SW_TIMESTAMPS | ++ CAPABILITY_BE3_NATIVE_ERX_API); ++ req->cap_flags = cpu_to_le32(CAPABILITY_BE3_NATIVE_ERX_API); ++ ++ status = be_mbox_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb); ++ adapter->be3_native = le32_to_cpu(resp->cap_flags) & ++ CAPABILITY_BE3_NATIVE_ERX_API; ++ } ++err: ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} ++ ++static void encode_port_names(struct be_adapter *adapter) ++{ ++ switch (adapter->port_name[adapter->hba_port_num]) { ++ case '0': ++ adapter->port_name[adapter->hba_port_num] = 0; ++ break; ++ case '1': ++ adapter->port_name[adapter->hba_port_num] = 1; ++ break; ++ case '2': ++ adapter->port_name[adapter->hba_port_num] = 2; ++ break; ++ case '3': ++ adapter->port_name[adapter->hba_port_num] = 3; ++ break; ++ case '4': ++ adapter->port_name[adapter->hba_port_num] = 4; ++ break; ++ case 'A': ++ adapter->port_name[adapter->hba_port_num] = 5; ++ break; ++ case 'B': ++ adapter->port_name[adapter->hba_port_num] = 6; ++ break; ++ case 'C': ++ adapter->port_name[adapter->hba_port_num] = 7; ++ break; ++ case 'D': ++ adapter->port_name[adapter->hba_port_num] = 8; ++ break; ++ } ++} ++ ++int be_cmd_query_port_names_v0(struct be_adapter *adapter, u8 *port_name) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_port_name *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_PORT_NAME); ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_PORT_NAME, sizeof(*req)); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb); ++ port_name[0] = resp->port0_name; ++ port_name[1] = resp->port1_name; ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ ++ if(!status) ++ encode_port_names(adapter); ++ return status; ++} ++ ++int be_cmd_query_port_names_v1(struct be_adapter *adapter, u8 *port_name) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_port_name *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_PORT_NAME); ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_PORT_NAME, sizeof(*req)); ++ req->hdr.version = 1; ++ + status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_port_name_v1 *resp = embedded_payload(wrb); ++ port_name[0] = resp->port0_name; ++ port_name[1] = resp->port1_name; ++ port_name[2] = resp->port2_name; ++ port_name[3] = resp->port3_name; ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ ++ if (!status) ++ encode_port_names(adapter); ++ return status; ++} ++ ++int be_cmd_req_pg_pfc(struct be_adapter *adapter, int *fw_num_txqs) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_pg *req; ++ int status, num = 0; ++ bool query = true; ++ ++ *fw_num_txqs = MAX_TX_QS; ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++enable_pfc: ++ wrb = wrb_from_mbox(adapter); ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_ETH_PG_FEATURE_QUERY_REQUEST); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, ++ OPCODE_ETH_PG_FEATURE_QUERY_REQUEST, sizeof(*req)); ++ ++ if (query) ++ req->query |= cpu_to_le32(REQ_PG_QUERY); ++ req->pfc_pg |= cpu_to_le32(REQ_PG_FEAT); ++ ++ status = be_mbox_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_pg *resp = embedded_payload(wrb); ++ if (query) { ++ if (le32_to_cpu(resp->pfc_pg) & REQ_PG_FEAT) { ++ num = le32_to_cpu(resp->num_tx_rings); ++ query = false; ++ goto enable_pfc; ++ } ++ } else { ++ adapter->flags |= BE_FLAGS_DCBX; ++ *fw_num_txqs = num; ++ } ++ } ++ ++ mutex_unlock(&adapter->mbox_lock); ++ return status; ++} ++ ++/* Set privilege(s) for a function */ ++int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 mask, u32 *prev, ++ u32 domain) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_fn_privileges *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_SET_FN_PRIVILEGES); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SET_FN_PRIVILEGES, sizeof(*req)); ++ ++ req->hdr.domain = domain; ++ req->privilege_mask = cpu_to_le32(mask); ++ ++ status = be_mcc_notify_wait(adapter); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Get privilege(s) for a function */ ++int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege, ++ u32 domain) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_fn_privileges *req; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_FN_PRIVILEGES); + ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_FN_PRIVILEGES, sizeof(*req)); ++ ++ req->hdr.domain = domain; ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_fn_privileges *resp = ++ embedded_payload(wrb); ++ *privilege = le32_to_cpu(resp->privilege_mask); ++ } else ++ *privilege = 0; ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Set Hyper switch config */ ++int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, ++ u32 domain, u16 intf_id) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_hsw_config *req; ++ void *ctxt; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ctxt = &req->context; ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_SET_HSW_CONFIG); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SET_HSW_CONFIG, sizeof(*req)); ++ ++ req->hdr.domain = domain; ++ AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, ctxt, intf_id); ++ if (pvid) { ++ AMAP_SET_BITS(struct amap_set_hsw_context, pvid_valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_set_hsw_context, pvid, ctxt, pvid); ++ } ++ ++ be_dws_cpu_to_le(req->context, sizeof(req->context)); ++ status = be_mcc_notify_wait(adapter); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Get Hyper switch config */ ++int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, ++ u32 domain, u16 intf_id) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_hsw_config *req; ++ void *ctxt; ++ int status; ++ u16 vid; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ctxt = &req->context; ++ ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_GET_HSW_CONFIG); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_HSW_CONFIG, sizeof(*req)); ++ ++ req->hdr.domain = domain; ++ AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, ctxt, ++ intf_id); ++ AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); ++ be_dws_cpu_to_le(req->context, sizeof(req->context)); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_hsw_config *resp = ++ embedded_payload(wrb); ++ be_dws_le_to_cpu(&resp->context, ++ sizeof(resp->context)); ++ vid = AMAP_GET_BITS(struct amap_get_hsw_resp_context, ++ pvid, &resp->context); ++ *pvid = le16_to_cpu(vid); ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_get_port_speed(struct be_adapter *adapter, ++ u8 port_num, u16 *dac_cable_len, u16 *port_speed) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_port_speed *req; ++ int status = 0; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_GET_LINK_SPEED); ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_NTWK_GET_LINK_SPEED, ++ sizeof(*req)); ++ req->port_num = port_num; ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_port_speed *resp = ++ embedded_payload(wrb); ++ *dac_cable_len = resp->dac_cable_length; ++ *port_speed = resp->mac_speed; ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++int be_cmd_set_port_speed_v1(struct be_adapter *adapter, ++ u8 port_num, u16 mac_speed, ++ u16 dac_cable_len) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_port_speed_v1 *req; ++ int status = 0; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, ++ OPCODE_COMMON_NTWK_SET_LINK_SPEED); ++ ++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_NTWK_SET_LINK_SPEED, ++ sizeof(*req)); ++ req->hdr.version=1; ++ ++ req->port_num = port_num; ++ req->virt_port = port_num; ++ req->mac_speed = mac_speed; ++ req->dac_cable_length = dac_cable_len; ++ status = be_mcc_notify_wait(adapter); ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++ ++/* Uses sync mcc */ ++#ifdef CONFIG_PALAU ++int be_cmd_pass_ext_ioctl(struct be_adapter *adapter, dma_addr_t dma, ++ int req_size, void *va) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_sge *sge; ++ int status; ++ struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *) va; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ sge = nonembedded_sgl(wrb); ++ ++ be_wrb_hdr_prepare(wrb, req_size, false, 1, hdr->opcode); ++ wrb->tag1 = MCC_WRB_PASS_THRU; ++ sge->pa_hi = cpu_to_le32(upper_32_bits(dma)); ++ sge->pa_lo = cpu_to_le32(dma & 0xFFFFFFFF); ++ sge->len = cpu_to_le32(req_size); ++ ++ status = be_mcc_notify_wait(adapter); ++err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } ++#endif +diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h +index ad33d55..35aa5c7 100644 +--- a/drivers/net/benet/be_cmds.h ++++ b/drivers/net/benet/be_cmds.h +@@ -1,20 +1,23 @@ + /* +- * Copyright (C) 2005 - 2009 ServerEngines ++ * Copyright (C) 2005 - 2011 Emulex + * 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 ++ * 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 ++ * linux-drivers@emulex.com + * +- * ServerEngines +- * 209 N. Fair Oaks Ave +- * Sunnyvale, CA 94085 ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 + */ + ++#ifndef BE_CMDS_H ++#define BE_CMDS_H ++ + /* + * The driver sends configuration and managements command requests to the + * firmware in the BE. These requests are communicated to the processor +@@ -29,9 +32,10 @@ struct be_sge { + u32 len; + }; + +-#define MCC_WRB_EMBEDDED_MASK 1 /* bit 0 of dword 0*/ ++#define MCC_WRB_EMBEDDED_MASK 1 /* bit 0 of dword 0*/ + #define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */ + #define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */ ++#define MCC_WRB_PASS_THRU 0xFF /* this wrb is used for pass thru cmd */ + struct be_mcc_wrb { + u32 embedded; /* dword 0 */ + u32 payload_length; /* dword 1 */ +@@ -44,24 +48,19 @@ struct be_mcc_wrb { + } payload; + }; + +-#define CQE_FLAGS_VALID_MASK (1 << 31) +-#define CQE_FLAGS_ASYNC_MASK (1 << 30) +-#define CQE_FLAGS_COMPLETED_MASK (1 << 28) +-#define CQE_FLAGS_CONSUMED_MASK (1 << 27) ++#define CQE_FLAGS_VALID_MASK (1 << 31) ++#define CQE_FLAGS_ASYNC_MASK (1 << 30) ++#define CQE_FLAGS_COMPLETED_MASK (1 << 28) ++#define CQE_FLAGS_CONSUMED_MASK (1 << 27) + + /* Completion Status */ + enum { +- MCC_STATUS_SUCCESS = 0x0, +-/* The client does not have sufficient privileges to execute the command */ +- MCC_STATUS_INSUFFICIENT_PRIVILEGES = 0x1, +-/* A parameter in the command was invalid. */ +- MCC_STATUS_INVALID_PARAMETER = 0x2, +-/* There are insufficient chip resources to execute the command */ +- MCC_STATUS_INSUFFICIENT_RESOURCES = 0x3, +-/* The command is completing because the queue was getting flushed */ +- MCC_STATUS_QUEUE_FLUSHING = 0x4, +-/* The command is completing with a DMA error */ +- MCC_STATUS_DMA_FAILED = 0x5, ++ MCC_STATUS_SUCCESS = 0, ++ MCC_STATUS_FAILED = 1, ++ MCC_STATUS_ILLEGAL_REQUEST = 2, ++ MCC_STATUS_ILLEGAL_FIELD = 3, ++ MCC_STATUS_INSUFFICIENT_BUFFER = 4, ++ MCC_STATUS_UNAUTHORIZED_REQUEST = 5, + MCC_STATUS_NOT_SUPPORTED = 66 + }; + +@@ -81,15 +80,24 @@ struct be_mcc_compl { + * mcc_compl is interpreted as follows: + */ + #define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */ ++#define ASYNC_TRAILER_EVENT_TYPE_SHIFT 16 /* bits 16 - 23 */ + #define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF ++#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xFF + #define ASYNC_EVENT_CODE_LINK_STATE 0x1 ++#define ASYNC_EVENT_CODE_GRP_5 0x5 ++#define ASYNC_EVENT_QOS_SPEED 0x1 ++#define ASYNC_EVENT_COS_PRIORITY 0x2 ++#define ASYNC_EVENT_PVID_STATE 0x3 ++#define GRP5_TYPE_PRIO_TC_MAP 4 ++ + struct be_async_event_trailer { + u32 code; + }; + + enum { +- ASYNC_EVENT_LINK_DOWN = 0x0, +- ASYNC_EVENT_LINK_UP = 0x1 ++ ASYNC_EVENT_LINK_DOWN = 0x0, ++ ASYNC_EVENT_LINK_UP = 0x1, ++ ASYNC_EVENT_LOGICAL = 0x2 + }; + + /* When the event code of an async trailer is link-state, the mcc_compl +@@ -101,7 +109,51 @@ struct be_async_event_link_state { + u8 port_duplex; + u8 port_speed; + u8 port_fault; +- u8 rsvd0[7]; ++ u8 rsvd0; ++ u16 qos_link_speed; ++ u32 event_tag; ++ struct be_async_event_trailer trailer; ++} __packed; ++ ++/* When the event code of an async trailer is GRP-5 and event_type is QOS_SPEED ++ * the mcc_compl must be interpreted as follows ++ */ ++struct be_async_event_grp5_qos_link_speed { ++ u8 physical_port; ++ u8 rsvd[5]; ++ u16 qos_link_speed; ++ u32 event_tag; ++ struct be_async_event_trailer trailer; ++} __packed; ++ ++/* When the event code of an async trailer is GRP5 and event type is ++ * CoS-Priority, the mcc_compl must be interpreted as follows ++ */ ++struct be_async_event_grp5_cos_priority { ++ u8 physical_port; ++ u8 available_priority_bmap; ++ u8 reco_default_priority; ++ u8 valid; ++ u8 rsvd0; ++ u8 event_tag; ++ struct be_async_event_trailer trailer; ++} __packed; ++ ++/* When the event code of an async trailer is GRP5 and event type is ++ * PVID state, the mcc_compl must be interpreted as follows ++ */ ++struct be_async_event_grp5_pvid_state { ++ u8 enabled; ++ u8 rsvd0; ++ u16 tag; ++ u32 event_tag; ++ u32 rsvd1; ++ struct be_async_event_trailer trailer; ++} __packed; ++ ++/* GRP5 prio-tc-map event */ ++struct be_async_event_grp5_prio_tc_map { ++ u8 prio_tc_map[8]; /* map[prio] -> tc_id */ + struct be_async_event_trailer trailer; + } __packed; + +@@ -111,41 +163,68 @@ struct be_mcc_mailbox { + }; + + #define CMD_SUBSYSTEM_COMMON 0x1 +-#define CMD_SUBSYSTEM_ETH 0x3 ++#define CMD_SUBSYSTEM_ETH 0x3 ++#define CMD_SUBSYSTEM_LOWLEVEL 0xb + + #define OPCODE_COMMON_NTWK_MAC_QUERY 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_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_CQ_CREATE 12 + #define OPCODE_COMMON_EQ_CREATE 13 +-#define OPCODE_COMMON_MCC_CREATE 21 +-#define OPCODE_COMMON_NTWK_RX_FILTER 34 ++#define OPCODE_COMMON_MCC_CREATE 21 ++#define OPCODE_COMMON_SET_QOS 28 ++#define OPCODE_COMMON_MCC_CREATE_EXT 90 ++#define OPCODE_COMMON_SEEPROM_READ 30 ++#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32 ++#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_FRAME_SIZE 39 + #define OPCODE_COMMON_MODIFY_EQ_DELAY 41 + #define OPCODE_COMMON_FIRMWARE_CONFIG 42 +-#define OPCODE_COMMON_NTWK_INTERFACE_CREATE 50 +-#define OPCODE_COMMON_NTWK_INTERFACE_DESTROY 51 +-#define OPCODE_COMMON_MCC_DESTROY 53 +-#define OPCODE_COMMON_CQ_DESTROY 54 +-#define OPCODE_COMMON_EQ_DESTROY 55 ++#define OPCODE_COMMON_NTWK_INTERFACE_CREATE 50 ++#define OPCODE_COMMON_NTWK_INTERFACE_DESTROY 51 ++#define OPCODE_COMMON_MCC_DESTROY 53 ++#define OPCODE_COMMON_CQ_DESTROY 54 ++#define OPCODE_COMMON_EQ_DESTROY 55 ++#define OPCODE_COMMON_NTWK_SET_LINK_SPEED 57 + #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 + #define OPCODE_COMMON_NTWK_PMAC_ADD 59 + #define OPCODE_COMMON_NTWK_PMAC_DEL 60 + #define OPCODE_COMMON_FUNCTION_RESET 61 ++#define OPCODE_COMMON_MANAGE_FAT 68 ++#define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69 ++#define OPCODE_COMMON_GET_BEACON_STATE 70 ++#define OPCODE_COMMON_READ_TRANSRECV_DATA 73 ++#define OPCODE_COMMON_GET_PORT_NAME 77 ++#define OPCODE_COMMON_SET_FN_PRIVILEGES 100 ++#define OPCODE_COMMON_GET_PHY_DETAILS 102 ++#define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103 ++#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 ++#define OPCODE_COMMON_NTWK_GET_LINK_SPEED 134 ++#define OPCODE_COMMON_GET_HSW_CONFIG 152 ++#define OPCODE_COMMON_SET_HSW_CONFIG 153 ++#define OPCODE_COMMON_GET_FN_PRIVILEGES 170 + ++#define OPCODE_ETH_RSS_CONFIG 1 + #define OPCODE_ETH_ACPI_CONFIG 2 + #define OPCODE_ETH_PROMISCUOUS 3 + #define OPCODE_ETH_GET_STATISTICS 4 + #define OPCODE_ETH_TX_CREATE 7 +-#define OPCODE_ETH_RX_CREATE 8 +-#define OPCODE_ETH_TX_DESTROY 9 +-#define OPCODE_ETH_RX_DESTROY 10 ++#define OPCODE_ETH_RX_CREATE 8 ++#define OPCODE_ETH_TX_DESTROY 9 ++#define OPCODE_ETH_RX_DESTROY 10 ++#define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12 ++#define OPCODE_ETH_PG_FEATURE_QUERY_REQUEST 23 ++ ++#define OPCODE_LOWLEVEL_HOST_DDR_DMA 17 ++#define OPCODE_LOWLEVEL_LOOPBACK_TEST 18 ++#define OPCODE_LOWLEVEL_SET_LOOPBACK_MODE 19 + + struct be_cmd_req_hdr { + u8 opcode; /* dword 0 */ +@@ -159,7 +238,7 @@ struct be_cmd_req_hdr { + }; + + #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */ +-#define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */ ++#define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */ + struct be_cmd_resp_hdr { + u32 info; /* dword 0 */ + u32 status; /* dword 1 */ +@@ -265,7 +344,7 @@ struct be_cmd_req_pmac_del { + /******************** Create CQ ***************************/ + /* Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field */ +-struct amap_cq_context { ++struct amap_cq_context_be { + u8 cidx[11]; /* dword 0*/ + u8 rsvd0; /* dword 0*/ + u8 coalescwm[2]; /* dword 0*/ +@@ -288,11 +367,28 @@ struct amap_cq_context { + u8 rsvd5[32]; /* dword 3*/ + } __packed; + ++struct amap_cq_context_lancer { ++ u8 rsvd0[12]; /* dword 0*/ ++ u8 coalescwm[2]; /* dword 0*/ ++ u8 nodelay; /* dword 0*/ ++ u8 rsvd1[12]; /* dword 0*/ ++ u8 count[2]; /* dword 0*/ ++ u8 valid; /* dword 0*/ ++ u8 rsvd2; /* dword 0*/ ++ u8 eventable; /* dword 0*/ ++ u8 eqid[16]; /* dword 1*/ ++ u8 rsvd3[15]; /* dword 1*/ ++ u8 armed; /* dword 1*/ ++ u8 rsvd4[32]; /* dword 2*/ ++ u8 rsvd5[32]; /* dword 3*/ ++} __packed; ++ + struct be_cmd_req_cq_create { + struct be_cmd_req_hdr hdr; + u16 num_pages; +- u16 rsvd0; +- u8 context[sizeof(struct amap_cq_context) / 8]; ++ u8 page_size; ++ u8 rsvd0; ++ u8 context[sizeof(struct amap_cq_context_be) / 8]; + struct phys_addr pages[8]; + } __packed; + +@@ -302,10 +398,28 @@ struct be_cmd_resp_cq_create { + u16 rsvd0; + } __packed; + ++struct be_cmd_req_get_fat { ++ struct be_cmd_req_hdr hdr; ++ u32 fat_operation; ++ u32 read_log_offset; ++ u32 read_log_length; ++ u32 data_buffer_size; ++ u32 data_buffer[1]; ++} __packed; ++ ++struct be_cmd_resp_get_fat { ++ struct be_cmd_resp_hdr hdr; ++ u32 log_size; ++ u32 read_log_length; ++ u32 rsvd[2]; ++ u32 data_buffer[1]; ++} __packed; ++ ++ + /******************** Create MCCQ ***************************/ + /* Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field */ +-struct amap_mcc_context { ++struct amap_mcc_context_be { + u8 con_index[14]; + u8 rsvd0[2]; + u8 ring_size[4]; +@@ -320,11 +434,31 @@ struct amap_mcc_context { + u8 rsvd2[32]; + } __packed; + ++struct amap_mcc_context_lancer { ++ u8 async_cq_id[16]; ++ u8 ring_size[4]; ++ u8 rsvd0[12]; ++ u8 rsvd1[31]; ++ u8 valid; ++ u8 async_cq_valid[1]; ++ u8 rsvd2[31]; ++ u8 rsvd3[32]; ++} __packed; ++ + struct be_cmd_req_mcc_create { + struct be_cmd_req_hdr hdr; + u16 num_pages; +- u16 rsvd0; +- u8 context[sizeof(struct amap_mcc_context) / 8]; ++ u16 cq_id; ++ u8 context[sizeof(struct amap_mcc_context_be) / 8]; ++ struct phys_addr pages[8]; ++} __packed; ++ ++struct be_cmd_req_mcc_ext_create { ++ struct be_cmd_req_hdr hdr; ++ u16 num_pages; ++ u16 cq_id; ++ u32 async_event_bitmap[1]; ++ u8 context[sizeof(struct amap_mcc_context_be) / 8]; + struct phys_addr pages[8]; + } __packed; + +@@ -335,49 +469,32 @@ struct be_cmd_resp_mcc_create { + } __packed; + + /******************** Create TxQ ***************************/ +-#define BE_ETH_TX_RING_TYPE_STANDARD 2 ++#define ETX_QUEUE_TYPE_STANDARD 0x2 ++#define ETX_QUEUE_TYPE_PRIORITY 0x10 + #define BE_ULP1_NUM 1 + +-/* Pseudo amap definition in which each bit of the actual structure is defined +- * as a byte: used to calculate offset/shift/mask of each field */ +-struct amap_tx_context { +- u8 rsvd0[16]; /* dword 0 */ +- u8 tx_ring_size[4]; /* dword 0 */ +- u8 rsvd1[26]; /* dword 0 */ +- u8 pci_func_id[8]; /* dword 1 */ +- u8 rsvd2[9]; /* dword 1 */ +- u8 ctx_valid; /* dword 1 */ +- u8 cq_id_send[16]; /* dword 2 */ +- u8 rsvd3[16]; /* dword 2 */ +- u8 rsvd4[32]; /* dword 3 */ +- u8 rsvd5[32]; /* dword 4 */ +- u8 rsvd6[32]; /* dword 5 */ +- u8 rsvd7[32]; /* dword 6 */ +- u8 rsvd8[32]; /* dword 7 */ +- u8 rsvd9[32]; /* dword 8 */ +- u8 rsvd10[32]; /* dword 9 */ +- u8 rsvd11[32]; /* dword 10 */ +- u8 rsvd12[32]; /* dword 11 */ +- u8 rsvd13[32]; /* dword 12 */ +- u8 rsvd14[32]; /* dword 13 */ +- u8 rsvd15[32]; /* dword 14 */ +- u8 rsvd16[32]; /* dword 15 */ +-} __packed; +- + struct be_cmd_req_eth_tx_create { + struct be_cmd_req_hdr hdr; + u8 num_pages; + u8 ulp_num; +- u8 type; +- u8 bound_port; +- u8 context[sizeof(struct amap_tx_context) / 8]; ++ u16 type; ++ u16 if_id; ++ u8 queue_size; ++ u8 rsvd1; ++ u32 rsvd2; ++ u16 cq_id; ++ u16 rsvd3; ++ u32 rsvd4[13]; + struct phys_addr pages[8]; + } __packed; + + struct be_cmd_resp_eth_tx_create { + struct be_cmd_resp_hdr hdr; + u16 cid; +- u16 rsvd0; ++ u16 rid; ++ u32 db_offset; ++ u8 tc_id; ++ u8 rsvd0[3]; + } __packed; + + /******************** Create RxQ ***************************/ +@@ -396,7 +513,7 @@ struct be_cmd_req_eth_rx_create { + struct be_cmd_resp_eth_rx_create { + struct be_cmd_resp_hdr hdr; + u16 id; +- u8 cpu_id; ++ u8 rss_id; + u8 rsvd0; + } __packed; + +@@ -429,14 +546,15 @@ enum be_if_flags { + BE_IF_FLAGS_VLAN = 0x100, + BE_IF_FLAGS_MCAST_PROMISCUOUS = 0x200, + BE_IF_FLAGS_PASS_L2_ERRORS = 0x400, +- BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800 ++ BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800, ++ BE_IF_FLAGS_MULTICAST = 0x1000 + }; + + /* An RX interface is an object with one or more MAC addresses and + * filtering capabilities. */ + struct be_cmd_req_if_create { + struct be_cmd_req_hdr hdr; +- u32 version; /* ignore currntly */ ++ u32 version; /* ignore currently */ + u32 capability_flags; + u32 enable_flags; + u8 mac_addr[ETH_ALEN]; +@@ -458,7 +576,7 @@ struct be_cmd_req_if_destroy { + }; + + /*************** HW Stats Get **********************************/ +-struct be_port_rxf_stats { ++struct be_port_rxf_stats_v0 { + u32 rx_bytes_lsd; /* dword 0*/ + u32 rx_bytes_msd; /* dword 1*/ + u32 rx_total_frames; /* dword 2*/ +@@ -527,8 +645,8 @@ struct be_port_rxf_stats { + u32 rx_input_fifo_overflow; /* dword 65*/ + }; + +-struct be_rxf_stats { +- struct be_port_rxf_stats port[2]; ++struct be_rxf_stats_v0 { ++ struct be_port_rxf_stats_v0 port[2]; + u32 rx_drops_no_pbuf; /* dword 132*/ + u32 rx_drops_no_txpb; /* dword 133*/ + u32 rx_drops_no_erx_descr; /* dword 134*/ +@@ -545,31 +663,51 @@ struct be_rxf_stats { + u32 rx_drops_invalid_ring; /* dword 145*/ + u32 forwarded_packets; /* dword 146*/ + u32 rx_drops_mtu; /* dword 147*/ +- u32 rsvd0[15]; ++ u32 rsvd0[7]; ++ u32 port0_jabber_events; ++ u32 port1_jabber_events; ++ u32 rsvd1[6]; + }; + +-struct be_erx_stats { ++struct be_erx_stats_v0 { + u32 rx_drops_no_fragments[44]; /* dwordS 0 to 43*/ +- u32 debug_wdma_sent_hold; /* dword 44*/ +- u32 debug_wdma_pbfree_sent_hold; /* dword 45*/ +- u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/ +- u32 debug_pmem_pbuf_dealloc; /* dword 47*/ ++ u32 rsvd[4]; + }; + +-struct be_hw_stats { +- struct be_rxf_stats rxf; ++struct be_pmem_stats { ++ u32 eth_red_drops; ++ u32 rsvd[5]; ++}; ++ ++struct be_hw_stats_v0 { ++ struct be_rxf_stats_v0 rxf; + u32 rsvd[48]; +- struct be_erx_stats erx; ++ struct be_erx_stats_v0 erx; ++ struct be_pmem_stats pmem; + }; + +-struct be_cmd_req_get_stats { ++struct be_cmd_req_get_stats_v0 { + struct be_cmd_req_hdr hdr; +- u8 rsvd[sizeof(struct be_hw_stats)]; ++ u8 rsvd[sizeof(struct be_hw_stats_v0)]; + }; + +-struct be_cmd_resp_get_stats { ++struct be_cmd_resp_get_stats_v0 { + struct be_cmd_resp_hdr hdr; +- struct be_hw_stats hw_stats; ++ struct be_hw_stats_v0 hw_stats; ++}; ++ ++struct be_cmd_req_get_cntl_addnl_attribs { ++ struct be_cmd_req_hdr hdr; ++ u8 rsvd[8]; ++}; ++ ++struct be_cmd_resp_get_cntl_addnl_attribs { ++ struct be_cmd_resp_hdr hdr; ++ u16 ipl_file_number; ++ u8 ipl_file_version; ++ u8 rsvd0; ++ u8 on_die_temperature; /* in degrees centigrade*/ ++ u8 rsvd1[3]; + }; + + struct be_cmd_req_vlan_config { +@@ -581,30 +719,22 @@ struct be_cmd_req_vlan_config { + u16 normal_vlan[64]; + } __packed; + +-struct be_cmd_req_promiscuous_config { +- struct be_cmd_req_hdr hdr; +- u8 port0_promiscuous; +- u8 port1_promiscuous; +- u16 rsvd0; +-} __packed; +- ++/******************** RX FILTER ******************************/ ++#define BE_MAX_MC 64 /* set mcast promisc if > 64 */ + struct macaddr { + u8 byte[ETH_ALEN]; + }; + +-struct be_cmd_req_mcast_mac_config { ++struct be_cmd_req_rx_filter { + struct be_cmd_req_hdr hdr; +- u16 num_mac; +- u8 promiscuous; +- u8 interface_id; +- struct macaddr mac[32]; +-} __packed; +- +-static inline struct be_hw_stats * +-hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd) +-{ +- return &cmd->hw_stats; +-} ++ u32 global_flags_mask; ++ u32 global_flags; ++ u32 if_flags_mask; ++ u32 if_flags; ++ u32 if_id; ++ u32 mcast_num; ++ struct macaddr mcast_mac[BE_MAX_MC]; ++}; + + /******************** Link Status Query *******************/ + struct be_cmd_req_link_status { +@@ -619,13 +749,18 @@ enum { + }; + + enum { +- PHY_LINK_SPEED_ZERO = 0x0, /* => No link */ ++ PHY_LINK_SPEED_ZERO = 0x0, /* => No link */ + PHY_LINK_SPEED_10MBPS = 0x1, + PHY_LINK_SPEED_100MBPS = 0x2, + PHY_LINK_SPEED_1GBPS = 0x3, + PHY_LINK_SPEED_10GBPS = 0x4 + }; + ++enum { ++ LINK_DOWN = 0x0, ++ LINK_UP = 0X1 ++}; ++ + struct be_cmd_resp_link_status { + struct be_cmd_resp_hdr hdr; + u8 physical_port; +@@ -634,9 +769,47 @@ struct be_cmd_resp_link_status { + u8 mac_fault; + u8 mgmt_mac_duplex; + u8 mgmt_mac_speed; +- u16 rsvd0; ++ u16 link_speed; ++ u32 logical_link_status; + } __packed; + ++/******************** Port Identification ***************************/ ++/* Identifies the type of port attached to NIC */ ++struct be_cmd_req_port_type { ++ struct be_cmd_req_hdr hdr; ++ u32 page_num; ++ u32 port; ++}; ++ ++enum { ++ TR_PAGE_A0 = 0xa0, ++ TR_PAGE_A2 = 0xa2 ++}; ++ ++struct be_cmd_resp_port_type { ++ struct be_cmd_resp_hdr hdr; ++ u32 page_num; ++ u32 port; ++ struct data { ++ u8 identifier; ++ u8 identifier_ext; ++ u8 connector; ++ u8 transceiver[8]; ++ u8 rsvd0[3]; ++ u8 length_km; ++ u8 length_hm; ++ u8 length_om1; ++ u8 length_om2; ++ u8 length_cu; ++ u8 length_cu_m; ++ u8 vendor_name[16]; ++ u8 rsvd; ++ u8 vendor_oui[3]; ++ u8 vendor_pn[16]; ++ u8 vendor_rev[4]; ++ } data; ++}; ++ + /******************** Get FW Version *******************/ + struct be_cmd_req_get_fw_version { + struct be_cmd_req_hdr hdr; +@@ -686,9 +859,13 @@ struct be_cmd_resp_modify_eq_delay { + } __packed; + + /******************** Get FW Config *******************/ ++#define FLEX10_MODE 0x400 ++#define VNIC_MODE 0x20000 ++#define UMC_ENABLED 0x1000000 ++ + struct be_cmd_req_query_fw_cfg { + struct be_cmd_req_hdr hdr; +- u32 rsvd[30]; ++ u32 rsvd[31]; + }; + + struct be_cmd_resp_query_fw_cfg { +@@ -696,10 +873,61 @@ struct be_cmd_resp_query_fw_cfg { + u32 be_config_number; + u32 asic_revision; + u32 phys_port; +- u32 function_cap; ++ u32 function_mode; + u32 rsvd[26]; ++ u32 function_caps; + }; + ++/******************** RSS Config *******************/ ++/* RSS types */ ++#define RSS_ENABLE_NONE 0x0 ++#define RSS_ENABLE_IPV4 0x1 ++#define RSS_ENABLE_TCP_IPV4 0x2 ++#define RSS_ENABLE_IPV6 0x4 ++#define RSS_ENABLE_TCP_IPV6 0x8 ++ ++struct be_cmd_req_rss_config { ++ struct be_cmd_req_hdr hdr; ++ u32 if_id; ++ u16 enable_rss; ++ u16 cpu_table_size_log2; ++ u32 hash[10]; ++ u8 cpu_table[128]; ++ u8 flush; ++ u8 rsvd0[3]; ++}; ++ ++/******************** Port Beacon ***************************/ ++ ++#define BEACON_STATE_ENABLED 0x1 ++#define BEACON_STATE_DISABLED 0x0 ++ ++struct be_cmd_req_enable_disable_beacon { ++ struct be_cmd_req_hdr hdr; ++ u8 port_num; ++ u8 beacon_state; ++ u8 beacon_duration; ++ u8 status_duration; ++} __packed; ++ ++struct be_cmd_resp_enable_disable_beacon { ++ struct be_cmd_resp_hdr resp_hdr; ++ u32 rsvd0; ++} __packed; ++ ++struct be_cmd_req_get_beacon_state { ++ struct be_cmd_req_hdr hdr; ++ u8 port_num; ++ u8 rsvd0; ++ u16 rsvd1; ++} __packed; ++ ++struct be_cmd_resp_get_beacon_state { ++ struct be_cmd_resp_hdr resp_hdr; ++ u8 beacon_state; ++ u8 rsvd0[3]; ++} __packed; ++ + /****************** Firmware Flash ******************/ + struct flashrom_params { + u32 op_code; +@@ -714,17 +942,468 @@ struct be_cmd_write_flashrom { + struct flashrom_params params; + }; + ++/************************ WOL *******************************/ ++struct be_cmd_req_acpi_wol_magic_config { ++ struct be_cmd_req_hdr hdr; ++ u32 rsvd0[145]; ++ u8 magic_mac[6]; ++ u8 rsvd2[2]; ++} __packed; ++ ++/********************** LoopBack test *********************/ ++struct be_cmd_req_loopback_test { ++ struct be_cmd_req_hdr hdr; ++ u32 loopback_type; ++ u32 num_pkts; ++ u64 pattern; ++ u32 src_port; ++ u32 dest_port; ++ u32 pkt_size; ++}; ++ ++struct be_cmd_resp_loopback_test { ++ struct be_cmd_resp_hdr resp_hdr; ++ u32 status; ++ u32 num_txfer; ++ u32 num_rx; ++ u32 miscomp_off; ++ u32 ticks_compl; ++}; ++ ++struct be_cmd_req_set_lmode { ++ struct be_cmd_req_hdr hdr; ++ u8 src_port; ++ u8 dest_port; ++ u8 loopback_type; ++ u8 loopback_state; ++}; ++ ++struct be_cmd_resp_set_lmode { ++ struct be_cmd_resp_hdr resp_hdr; ++ u8 rsvd0[4]; ++}; ++ ++/********************** DDR DMA test *********************/ ++struct be_cmd_req_ddrdma_test { ++ struct be_cmd_req_hdr hdr; ++ u64 pattern; ++ u32 byte_count; ++ u32 rsvd0; ++ u8 snd_buff[4096]; ++ u8 rsvd1[4096]; ++}; ++ ++struct be_cmd_resp_ddrdma_test { ++ struct be_cmd_resp_hdr hdr; ++ u64 pattern; ++ u32 byte_cnt; ++ u32 snd_err; ++ u8 rsvd0[4096]; ++ u8 rcv_buff[4096]; ++}; ++ ++/*********************** SEEPROM Read ***********************/ ++ ++#define BE_READ_SEEPROM_LEN 1024 ++struct be_cmd_req_seeprom_read { ++ struct be_cmd_req_hdr hdr; ++ u8 rsvd0[BE_READ_SEEPROM_LEN]; ++}; ++ ++struct be_cmd_resp_seeprom_read { ++ struct be_cmd_req_hdr hdr; ++ u8 seeprom_data[BE_READ_SEEPROM_LEN]; ++}; ++ ++enum { ++ PHY_TYPE_CX4_10GB = 0, ++ PHY_TYPE_XFP_10GB, ++ PHY_TYPE_SFP_1GB, ++ PHY_TYPE_SFP_PLUS_10GB, ++ PHY_TYPE_KR_10GB, ++ PHY_TYPE_KX4_10GB, ++ PHY_TYPE_BASET_10GB, ++ PHY_TYPE_BASET_1GB, ++ PHY_TYPE_BASEX_1GB, ++ PHY_TYPE_SGMII, ++ PHY_TYPE_DISABLED = 255 ++}; ++ ++#define BE_AN_EN 0x2 ++#define BE_PAUSE_SYM_EN 0x80 ++ ++struct be_cmd_req_get_phy_info { ++ struct be_cmd_req_hdr hdr; ++ u8 rsvd0[24]; ++}; ++ ++struct be_phy_info { ++ u16 phy_type; ++ u16 interface_type; ++ u32 misc_params; ++ u16 ext_phy_details; ++ u16 rsvd; ++ u16 auto_speeds_supported; ++ u16 fixed_speeds_supported; ++ u32 future_use[2]; ++}; ++ ++struct be_cmd_resp_get_phy_info { ++ struct be_cmd_req_hdr hdr; ++ struct be_phy_info phy_info; ++}; ++ ++/*********************** Set QOS ***********************/ ++ ++#define BE_QOS_BITS_NIC 1 ++ ++struct be_cmd_req_set_qos { ++ struct be_cmd_req_hdr hdr; ++ u32 valid_bits; ++ u32 max_bps_nic; ++ u32 rsvd[7]; ++}; ++ ++struct be_cmd_resp_set_qos { ++ struct be_cmd_resp_hdr hdr; ++ u32 rsvd; ++}; ++ ++/*********************** Controller Attributes ***********************/ ++struct be_cmd_req_cntl_attribs { ++ struct be_cmd_req_hdr hdr; ++}; ++ ++struct be_cmd_resp_cntl_attribs { ++ struct be_cmd_resp_hdr hdr; ++ struct mgmt_controller_attrib attribs; ++}; ++ ++/******************* get port names ***************/ ++struct be_cmd_req_get_port_name { ++ struct be_cmd_req_hdr hdr; ++ u32 rsvd0; ++}; ++ ++struct be_cmd_resp_get_port_name { ++ struct be_cmd_req_hdr hdr; ++ u8 port0_name; ++ u8 port1_name; ++ u8 rsvd0[2]; ++}; ++ ++struct be_cmd_resp_get_port_name_v1 { ++ struct be_cmd_req_hdr hdr; ++ u32 pt : 2; ++ u32 rsvd0 : 30; ++ u8 port0_name; ++ u8 port1_name; ++ u8 port2_name; ++ u8 port3_name; ++}; ++ ++/*********************** Set driver function ***********************/ ++#define CAPABILITY_SW_TIMESTAMPS 2 ++#define CAPABILITY_BE3_NATIVE_ERX_API 4 ++ ++struct be_cmd_req_set_func_cap { ++ struct be_cmd_req_hdr hdr; ++ u32 valid_cap_flags; ++ u32 cap_flags; ++ u8 rsvd[212]; ++}; ++ ++struct be_cmd_resp_set_func_cap { ++ struct be_cmd_resp_hdr hdr; ++ u32 valid_cap_flags; ++ u32 cap_flags; ++ u8 rsvd[212]; ++}; ++ ++/*********************** PG Query Request ****************************/ ++#define REQ_PG_QUERY 0x1 ++#define REQ_PG_FEAT 0x1 ++struct be_cmd_req_pg { ++ struct be_cmd_req_hdr hdr; ++ u32 query; ++ u32 pfc_pg; ++}; ++ ++struct be_cmd_resp_pg { ++ struct be_cmd_resp_hdr hdr; ++ u32 pfc_pg; ++ u32 num_tx_rings; ++}; ++ ++/*********************** Function Privileges ***********************/ ++enum { ++ BE_PRIV_DEFAULT = 0x1, ++ BE_PRIV_LNKQUERY = 0x2, ++ BE_PRIV_LNKSTATS = 0x4, ++ BE_PRIV_LNKMGMT = 0x8, ++ BE_PRIV_LNKDIAG = 0x10, ++ BE_PRIV_UTILQUERY = 0x20, ++ BE_PRIV_FILTMGMT = 0x40, ++ BE_PRIV_IFACEMGMT = 0x80, ++ BE_PRIV_VHADM = 0x100, ++ BE_PRIV_DEVCFG = 0x200, ++ BE_PRIV_DEVSEC = 0x400 ++}; ++ ++struct be_cmd_req_get_fn_privileges { ++ struct be_cmd_req_hdr hdr; ++ u32 rsvd; ++}; ++ ++struct be_cmd_resp_get_fn_privileges { ++ struct be_cmd_resp_hdr hdr; ++ u32 privilege_mask; ++}; ++ ++struct be_cmd_req_set_fn_privileges { ++ struct be_cmd_req_hdr hdr; ++ u32 privilege_mask; ++}; ++ ++struct be_cmd_resp_set_fn_privileges { ++ struct be_cmd_resp_hdr hdr; ++ u32 prev_privilege_mask; ++}; ++ ++/*********************** HSW Config ***********************/ ++struct amap_set_hsw_context { ++ u8 interface_id[16]; ++ u8 rsvd0[14]; ++ u8 pvid_valid; ++ u8 rsvd1; ++ u8 rsvd2[16]; ++ u8 pvid[16]; ++ u8 rsvd3[32]; ++ u8 rsvd4[32]; ++ u8 rsvd5[32]; ++} __packed; ++ ++struct be_cmd_req_set_hsw_config { ++ struct be_cmd_req_hdr hdr; ++ u8 context[sizeof(struct amap_set_hsw_context) / 8]; ++} __packed; ++ ++struct be_cmd_resp_set_hsw_config { ++ struct be_cmd_resp_hdr hdr; ++ u32 rsvd; ++}; ++ ++struct amap_get_hsw_req_context { ++ u8 interface_id[16]; ++ u8 rsvd0[14]; ++ u8 pvid_valid; ++ u8 pport; ++} __packed; ++ ++struct amap_get_hsw_resp_context { ++ u8 rsvd1[16]; ++ u8 pvid[16]; ++ u8 rsvd2[32]; ++ u8 rsvd3[32]; ++ u8 rsvd4[32]; ++} __packed; ++ ++struct be_cmd_req_get_hsw_config { ++ struct be_cmd_req_hdr hdr; ++ u8 context[sizeof(struct amap_get_hsw_req_context) / 8]; ++} __packed; ++ ++struct be_cmd_resp_get_hsw_config { ++ struct be_cmd_resp_hdr hdr; ++ u8 context[sizeof(struct amap_get_hsw_resp_context) / 8]; ++ u32 rsvd; ++}; ++ ++/*************** Set speed ********************/ ++struct be_cmd_req_set_port_speed_v1 { ++ struct be_cmd_req_hdr hdr; ++ u8 port_num; ++ u8 virt_port; ++ u16 mac_speed; ++ u16 dac_cable_length; ++ u16 rsvd0; ++}; ++ ++struct be_cmd_resp_set_port_speed_v1 { ++ struct be_cmd_resp_hdr hdr; ++ u32 rsvd0; ++}; ++ ++/************** get port speed *******************/ ++struct be_cmd_req_get_port_speed { ++ struct be_cmd_req_hdr hdr; ++ u8 port_num; ++}; ++ ++struct be_cmd_resp_get_port_speed { ++ struct be_cmd_req_hdr hdr; ++ u16 mac_speed; ++ u16 dac_cable_length; ++}; ++ ++/*************** HW Stats Get v1 **********************************/ ++#define BE_TXP_SW_SZ 48 ++struct be_port_rxf_stats_v1 { ++ u32 rsvd0[12]; ++ u32 rx_crc_errors; ++ u32 rx_alignment_symbol_errors; ++ u32 rx_pause_frames; ++ u32 rx_priority_pause_frames; ++ u32 rx_control_frames; ++ u32 rx_in_range_errors; ++ u32 rx_out_range_errors; ++ u32 rx_frame_too_long; ++ u32 rx_address_match_errors; ++ u32 rx_dropped_too_small; ++ u32 rx_dropped_too_short; ++ u32 rx_dropped_header_too_small; ++ u32 rx_dropped_tcp_length; ++ u32 rx_dropped_runt; ++ u32 rsvd1[10]; ++ u32 rx_ip_checksum_errs; ++ u32 rx_tcp_checksum_errs; ++ u32 rx_udp_checksum_errs; ++ u32 rsvd2[7]; ++ u32 rx_switched_unicast_packets; ++ u32 rx_switched_multicast_packets; ++ u32 rx_switched_broadcast_packets; ++ u32 rsvd3[3]; ++ u32 tx_pauseframes; ++ u32 tx_priority_pauseframes; ++ u32 tx_controlframes; ++ u32 rsvd4[10]; ++ u32 rxpp_fifo_overflow_drop; ++ u32 rx_input_fifo_overflow_drop; ++ u32 pmem_fifo_overflow_drop; ++ u32 jabber_events; ++ u32 rsvd5[3]; ++}; ++ ++ ++struct be_rxf_stats_v1 { ++ struct be_port_rxf_stats_v1 port[4]; ++ u32 rsvd0[2]; ++ u32 rx_drops_no_pbuf; ++ u32 rx_drops_no_txpb; ++ u32 rx_drops_no_erx_descr; ++ u32 rx_drops_no_tpre_descr; ++ u32 rsvd1[6]; ++ u32 rx_drops_too_many_frags; ++ u32 rx_drops_invalid_ring; ++ u32 forwarded_packets; ++ u32 rx_drops_mtu; ++ u32 rsvd2[14]; ++}; ++ ++struct be_erx_stats_v1 { ++ u32 rx_drops_no_fragments[68]; /* dwordS 0 to 67*/ ++ u32 rsvd[4]; ++}; ++ ++struct be_hw_stats_v1 { ++ struct be_rxf_stats_v1 rxf; ++ u32 rsvd0[BE_TXP_SW_SZ]; ++ struct be_erx_stats_v1 erx; ++ struct be_pmem_stats pmem; ++ u32 rsvd1[3]; ++}; ++ ++struct be_cmd_req_get_stats_v1 { ++ struct be_cmd_req_hdr hdr; ++ u8 rsvd[sizeof(struct be_hw_stats_v1)]; ++}; ++ ++struct be_cmd_resp_get_stats_v1 { ++ struct be_cmd_resp_hdr hdr; ++ struct be_hw_stats_v1 hw_stats; ++}; ++ ++static inline void * ++hw_stats_from_cmd(struct be_adapter *adapter) ++{ ++ if (adapter->generation == BE_GEN3) { ++ struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va; ++ ++ return &cmd->hw_stats; ++ } else { ++ struct be_cmd_resp_get_stats_v0 *cmd = adapter->stats_cmd.va; ++ ++ return &cmd->hw_stats; ++ } ++} ++ ++static inline void *be_port_rxf_stats_from_cmd(struct be_adapter *adapter) ++{ ++ if (adapter->generation == BE_GEN3) { ++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); ++ struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf; ++ ++ return &rxf_stats->port[adapter->port_num]; ++ } else { ++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); ++ struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf; ++ ++ return &rxf_stats->port[adapter->port_num]; ++ } ++} ++ ++static inline void *be_rxf_stats_from_cmd(struct be_adapter *adapter) ++{ ++ if (adapter->generation == BE_GEN3) { ++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); ++ ++ return &hw_stats->rxf; ++ } else { ++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); ++ ++ return &hw_stats->rxf; ++ } ++} ++ ++static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter) ++{ ++ if (adapter->generation == BE_GEN3) { ++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); ++ ++ return &hw_stats->erx; ++ } else { ++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); ++ ++ return &hw_stats->erx; ++ } ++} ++ ++static inline void *be_pmem_stats_from_cmd(struct be_adapter *adapter) ++{ ++ if (adapter->generation == BE_GEN3) { ++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); ++ ++ return &hw_stats->pmem; ++ } else { ++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); ++ ++ return &hw_stats->pmem; ++ } ++} ++ + extern int be_pci_fnum_get(struct be_adapter *adapter); + extern int be_cmd_POST(struct be_adapter *adapter); + extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, + u8 type, bool permanent, u32 if_handle); + extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, +- u32 if_id, u32 *pmac_id); +-extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id); ++ u32 if_id, u32 *pmac_id, u32 domain); ++extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, ++ u32 domain); + extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, + u32 en_flags, u8 *mac, bool pmac_invalid, +- u32 *if_handle, u32 *pmac_id); +-extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle); ++ u32 *if_handle, u32 *pmac_id, u32 domain); ++extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle, ++ u32 domain); + extern int be_cmd_eq_create(struct be_adapter *adapter, + struct be_queue_info *eq, int eq_delay); + extern int be_cmd_cq_create(struct be_adapter *adapter, +@@ -736,36 +1415,92 @@ extern int be_cmd_mccq_create(struct be_adapter *adapter, + struct be_queue_info *cq); + extern int be_cmd_txq_create(struct be_adapter *adapter, + struct be_queue_info *txq, +- struct be_queue_info *cq); ++ struct be_queue_info *cq, u8 *tc_id); + extern int be_cmd_rxq_create(struct be_adapter *adapter, + struct be_queue_info *rxq, u16 cq_id, + u16 frag_size, u16 max_frame_size, u32 if_id, +- u32 rss); ++ u32 rss, u8 *rss_id); + extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + int type); ++extern int be_cmd_rxq_destroy(struct be_adapter *adapter, ++ struct be_queue_info *q); + extern int be_cmd_link_status_query(struct be_adapter *adapter, +- bool *link_up); ++ int *link_status, u8 *mac_speed, u16 *link_speed, u32 dom); + extern int be_cmd_reset(struct be_adapter *adapter); + extern int be_cmd_get_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd); +-extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver); ++extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, ++ char *fw_on_flash); + + extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); + extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, + u16 *vtag_array, u32 num, bool untagged, + bool promiscuous); +-extern int be_cmd_promiscuous_config(struct be_adapter *adapter, +- u8 port_num, bool en); +-extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, +- struct dev_mc_list *mc_list, u32 mc_count); ++extern int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status); + extern int be_cmd_set_flow_control(struct be_adapter *adapter, + u32 tx_fc, u32 rx_fc); + extern int be_cmd_get_flow_control(struct be_adapter *adapter, + u32 *tx_fc, u32 *rx_fc); +-extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, +- u32 *port_num, u32 *cap); ++extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, ++ u32 *function_mode, u32 *functions_caps); + extern int be_cmd_reset_function(struct be_adapter *adapter); +-extern int be_process_mcc(struct be_adapter *adapter); ++extern int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, ++ u16 table_size); ++extern int be_process_mcc(struct be_adapter *adapter, int *status); ++extern int be_cmd_set_beacon_state(struct be_adapter *adapter, ++ u8 port_num, u8 beacon, u8 status, u8 state); ++extern int be_cmd_get_beacon_state(struct be_adapter *adapter, ++ u8 port_num, u32 *state); ++extern int be_cmd_read_port_type(struct be_adapter *adapter, u32 port, ++ u8 *connector); + extern int be_cmd_write_flashrom(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 flash_oper, + u32 flash_opcode, u32 buf_size); ++int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, ++ int offset); ++extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, ++ struct be_dma_mem *nonemb_cmd); ++extern int be_cmd_fw_init(struct be_adapter *adapter); ++extern int be_cmd_fw_clean(struct be_adapter *adapter); ++extern void be_async_mcc_enable(struct be_adapter *adapter); ++extern void be_async_mcc_disable(struct be_adapter *adapter); ++extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, ++ u32 loopback_type, u32 pkt_size, ++ u32 num_pkts, u64 pattern); ++extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, ++ u32 byte_cnt, struct be_dma_mem *cmd); ++extern int be_cmd_get_seeprom_data(struct be_adapter *adapter, ++ struct be_dma_mem *nonemb_cmd); ++extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, ++ u8 loopback_type, u8 enable); ++extern int be_cmd_get_phy_info(struct be_adapter *adapter, ++ struct be_phy_info *phy_info); ++extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain); ++extern void be_detect_dump_ue(struct be_adapter *adapter); ++extern int be_cmd_get_die_temperature(struct be_adapter *adapter); ++extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); ++extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); ++extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); ++extern int be_cmd_req_native_mode(struct be_adapter *adapter); ++extern int be_cmd_query_port_names_v0(struct be_adapter *adapter, u8 *port_name); ++extern int be_cmd_query_port_names_v1(struct be_adapter *adapter, u8 *port_name); ++extern int be_cmd_req_pg_pfc(struct be_adapter *adapter, int *fw_num_txqs); ++ ++extern int be_cmd_get_fn_privileges(struct be_adapter *adapter, ++ u32 *privilege, u32 domain); ++extern int be_cmd_set_fn_privileges(struct be_adapter *adapter, ++ u32 mask, u32 *prev, u32 domain); ++extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, ++ u32 domain, u16 intf_id); ++extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, ++ u32 domain, u16 intf_id); ++extern int be_cmd_set_port_speed_v1(struct be_adapter *adapter, u8 port_num, ++ u16 mac_speed, u16 dac_cable_len); ++extern int be_cmd_get_port_speed(struct be_adapter *adapter, u8 port_num, ++ u16 *dac_cable_len, u16 *port_speed); ++#ifdef CONFIG_PALAU ++int be_cmd_pass_ext_ioctl(struct be_adapter *adapter, dma_addr_t dma, ++ int req_size, void *va); ++#endif ++ ++#endif /* !BE_CMDS_H */ +diff --git a/drivers/net/benet/be_compat.c b/drivers/net/benet/be_compat.c +new file mode 100644 +index 0000000..bdd1dba +--- /dev/null ++++ b/drivers/net/benet/be_compat.c +@@ -0,0 +1,630 @@ ++/* ++ * Copyright (C) 2005 - 2011 Emulex ++ * 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@emulex.com ++ * ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 ++ */ ++ ++#include "be.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) ++void be_netdev_ops_init(struct net_device *netdev, struct net_device_ops *ops) ++{ ++ netdev->open = ops->ndo_open; ++ netdev->stop = ops->ndo_stop; ++ netdev->hard_start_xmit = ops->ndo_start_xmit; ++ netdev->set_mac_address = ops->ndo_set_mac_address; ++ netdev->get_stats = ops->ndo_get_stats; ++ netdev->set_multicast_list = ops->ndo_set_rx_mode; ++ netdev->change_mtu = ops->ndo_change_mtu; ++ netdev->vlan_rx_register = ops->ndo_vlan_rx_register; ++ netdev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid; ++ netdev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid; ++ netdev->do_ioctl = ops->ndo_do_ioctl; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ netdev->poll_controller = ops->ndo_poll_controller; ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netdev->select_queue = ops->ndo_select_queue; ++#endif ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) ++int eth_validate_addr(struct net_device *netdev) ++{ ++ return 0; ++} ++#endif ++ ++/* New NAPI backport */ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24) ++ ++int be_poll_compat(struct net_device *netdev, int *budget) ++{ ++ struct napi_struct *napi = netdev->priv; ++ u32 work_done, can_do; ++ ++ can_do = min(*budget, netdev->quota); ++ work_done = napi->poll(napi, can_do); ++ ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ if (napi->rx) ++ return (work_done >= can_do); ++ return 0; ++} ++ ++ ++#endif /* New NAPI backport */ ++ ++int be_netif_napi_add(struct net_device *netdev, ++ struct napi_struct *napi, ++ int (*poll) (struct napi_struct *, int), int weight) ++{ ++#ifdef HAVE_SIMULATED_MULTI_NAPI ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct net_device *nd; ++ ++ nd = alloc_netdev(0, "", ether_setup); ++ if (!nd) ++ return -ENOMEM; ++ nd->priv = napi; ++ nd->weight = BE_NAPI_WEIGHT; ++ nd->poll = be_poll_compat; ++ set_bit(__LINK_STATE_START, &nd->state); ++ ++ if (napi == &adapter->rx_obj[0].rx_eq.napi) ++ napi->rx = true; ++ napi->poll = poll; ++ napi->dev = nd; ++#ifdef RHEL_NEW_NAPI ++ napi->napi.dev = netdev; ++#endif ++ return 0; ++#else ++ netif_napi_add(netdev, napi, poll, weight); ++ return 0; ++#endif ++} ++void be_netif_napi_del(struct net_device *netdev) ++{ ++#ifdef HAVE_SIMULATED_MULTI_NAPI ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct napi_struct *napi; ++ struct be_rx_obj *rxo; ++ int i; ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ napi = &rxo->rx_eq.napi; ++ if (napi->dev) { ++ free_netdev(napi->dev); ++ napi->dev = NULL; ++ } ++ } ++ ++ napi = &adapter->tx_eq.napi; ++ if (napi->dev) { ++ free_netdev(napi->dev); ++ napi->dev = NULL; ++ } ++#endif ++} ++/* INET_LRO backport */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) ++ ++#define TCP_HDR_LEN(tcph) (tcph->doff << 2) ++#define IP_HDR_LEN(iph) (iph->ihl << 2) ++#define TCP_PAYLOAD_LENGTH(iph, tcph) (ntohs(iph->tot_len) - IP_HDR_LEN(iph) \ ++ - TCP_HDR_LEN(tcph)) ++ ++#define IPH_LEN_WO_OPTIONS 5 ++#define TCPH_LEN_WO_OPTIONS 5 ++#define TCPH_LEN_W_TIMESTAMP 8 ++ ++#define LRO_MAX_PG_HLEN 64 ++#define LRO_INC_STATS(lro_mgr, attr) { lro_mgr->stats.attr++; } ++/* ++ * Basic tcp checks whether packet is suitable for LRO ++ */ ++static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph, ++ int len, struct net_lro_desc *lro_desc) ++{ ++ /* check ip header: don't aggregate padded frames */ ++ if (ntohs(iph->tot_len) != len) ++ return -1; ++ ++ if (iph->ihl != IPH_LEN_WO_OPTIONS) ++ return -1; ++ ++ if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack ++ || tcph->rst || tcph->syn || tcph->fin) ++ return -1; ++ ++ if (INET_ECN_is_ce(ipv4_get_dsfield(iph))) ++ return -1; ++ ++ if (tcph->doff != TCPH_LEN_WO_OPTIONS ++ && tcph->doff != TCPH_LEN_W_TIMESTAMP) ++ return -1; ++ ++ /* check tcp options (only timestamp allowed) */ ++ if (tcph->doff == TCPH_LEN_W_TIMESTAMP) { ++ u32 *topt = (u32 *)(tcph + 1); ++ ++ if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) ++ | (TCPOPT_TIMESTAMP << 8) ++ | TCPOLEN_TIMESTAMP)) ++ return -1; ++ ++ /* timestamp should be in right order */ ++ topt++; ++ if (lro_desc && after(ntohl(lro_desc->tcp_rcv_tsval), ++ ntohl(*topt))) ++ return -1; ++ ++ /* timestamp reply should not be zero */ ++ topt++; ++ if (*topt == 0) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc) ++{ ++ struct iphdr *iph = lro_desc->iph; ++ struct tcphdr *tcph = lro_desc->tcph; ++ u32 *p; ++ __wsum tcp_hdr_csum; ++ ++ tcph->ack_seq = lro_desc->tcp_ack; ++ tcph->window = lro_desc->tcp_window; ++ ++ if (lro_desc->tcp_saw_tstamp) { ++ p = (u32 *)(tcph + 1); ++ *(p+2) = lro_desc->tcp_rcv_tsecr; ++ } ++ ++ iph->tot_len = htons(lro_desc->ip_tot_len); ++ ++ iph->check = 0; ++ iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl); ++ ++ tcph->check = 0; ++ tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0); ++ lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum); ++ tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ++ lro_desc->ip_tot_len - ++ IP_HDR_LEN(iph), IPPROTO_TCP, ++ lro_desc->data_csum); ++} ++ ++static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len) ++{ ++ __wsum tcp_csum; ++ __wsum tcp_hdr_csum; ++ __wsum tcp_ps_hdr_csum; ++ ++ tcp_csum = ~csum_unfold(tcph->check); ++ tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum); ++ ++ tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, ++ len + TCP_HDR_LEN(tcph), ++ IPPROTO_TCP, 0); ++ ++ return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum), ++ tcp_ps_hdr_csum); ++} ++ ++static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb, ++ struct iphdr *iph, struct tcphdr *tcph, ++ u16 vlan_tag, struct vlan_group *vgrp) ++{ ++ int nr_frags; ++ u32 *ptr; ++ u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); ++ ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ lro_desc->parent = skb; ++ lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]); ++ lro_desc->iph = iph; ++ lro_desc->tcph = tcph; ++ lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len; ++ lro_desc->tcp_ack = ntohl(tcph->ack_seq); ++ lro_desc->tcp_window = tcph->window; ++ ++ lro_desc->pkt_aggr_cnt = 1; ++ lro_desc->ip_tot_len = ntohs(iph->tot_len); ++ ++ if (tcph->doff == 8) { ++ ptr = (u32 *)(tcph+1); ++ lro_desc->tcp_saw_tstamp = 1; ++ lro_desc->tcp_rcv_tsval = *(ptr+1); ++ lro_desc->tcp_rcv_tsecr = *(ptr+2); ++ } ++ ++ lro_desc->mss = tcp_data_len; ++ lro_desc->vgrp = vgrp; ++ lro_desc->vlan_tag = vlan_tag; ++ lro_desc->active = 1; ++ ++ if (tcp_data_len) ++ lro_desc->data_csum = lro_tcp_data_csum(iph, tcph, ++ tcp_data_len); ++ ++ if (!tcp_data_len) ++ lro_desc->ack_cnt++; ++} ++ ++static inline void lro_clear_desc(struct net_lro_desc *lro_desc) ++{ ++ memset(lro_desc, 0, sizeof(struct net_lro_desc)); ++} ++ ++static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph, ++ struct tcphdr *tcph, int tcp_data_len) ++{ ++ struct sk_buff *parent = lro_desc->parent; ++ u32 *topt; ++ ++ lro_desc->pkt_aggr_cnt++; ++ lro_desc->ip_tot_len += tcp_data_len; ++ lro_desc->tcp_next_seq += tcp_data_len; ++ lro_desc->tcp_window = tcph->window; ++ lro_desc->tcp_ack = tcph->ack_seq; ++ ++ /* don't update tcp_rcv_tsval, would not work with PAWS */ ++ if (lro_desc->tcp_saw_tstamp) { ++ topt = (u32 *) (tcph + 1); ++ lro_desc->tcp_rcv_tsecr = *(topt + 2); ++ } ++ ++ if (tcp_data_len) ++ lro_desc->data_csum = csum_block_add(lro_desc->data_csum, ++ lro_tcp_data_csum(iph, tcph, ++ tcp_data_len), ++ parent->len); ++ ++ parent->len += tcp_data_len; ++ parent->data_len += tcp_data_len; ++ if (tcp_data_len > lro_desc->mss) ++ lro_desc->mss = tcp_data_len; ++} ++ ++static void lro_add_frags(struct net_lro_desc *lro_desc, ++ int len, int hlen, int truesize, ++ struct skb_frag_struct *skb_frags, ++ struct iphdr *iph, struct tcphdr *tcph) ++{ ++ struct sk_buff *skb = lro_desc->parent; ++ int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); ++ ++ lro_add_common(lro_desc, iph, tcph, tcp_data_len); ++ ++ skb->truesize += truesize; ++ ++ if (!tcp_data_len) { ++ put_page(skb_frags[0].page); ++ lro_desc->ack_cnt++; ++ return; ++ } ++ ++ skb_frags[0].page_offset += hlen; ++ skb_frags[0].size -= hlen; ++ ++ while (tcp_data_len > 0) { ++ *(lro_desc->next_frag) = *skb_frags; ++ tcp_data_len -= skb_frags->size; ++ lro_desc->next_frag++; ++ skb_frags++; ++ skb_shinfo(skb)->nr_frags++; ++ } ++} ++ ++static int lro_check_tcp_conn(struct net_lro_desc *lro_desc, ++ struct iphdr *iph, ++ struct tcphdr *tcph) ++{ ++ if ((lro_desc->iph->saddr != iph->saddr) ++ || (lro_desc->iph->daddr != iph->daddr) ++ || (lro_desc->tcph->source != tcph->source) ++ || (lro_desc->tcph->dest != tcph->dest)) ++ return -1; ++ return 0; ++} ++ ++static struct net_lro_desc *lro_get_desc(struct net_lro_mgr *lro_mgr, ++ struct net_lro_desc *lro_arr, ++ struct iphdr *iph, ++ struct tcphdr *tcph) ++{ ++ struct net_lro_desc *lro_desc = NULL; ++ struct net_lro_desc *tmp; ++ int max_desc = lro_mgr->max_desc; ++ int i; ++ ++ for (i = 0; i < max_desc; i++) { ++ tmp = &lro_arr[i]; ++ if (tmp->active) ++ if (!lro_check_tcp_conn(tmp, iph, tcph)) { ++ lro_desc = tmp; ++ goto out; ++ } ++ } ++ ++ for (i = 0; i < max_desc; i++) { ++ if (!lro_arr[i].active) { ++ lro_desc = &lro_arr[i]; ++ goto out; ++ } ++ } ++ ++ LRO_INC_STATS(lro_mgr, no_desc); ++out: ++ return lro_desc; ++} ++ ++static void lro_flush(struct net_lro_mgr *lro_mgr, ++ struct net_lro_desc *lro_desc) ++{ ++ struct be_adapter *adapter = netdev_priv(lro_mgr->dev); ++ ++ if (lro_desc->pkt_aggr_cnt > 1) ++ lro_update_tcp_ip_header(lro_desc); ++ ++ skb_shinfo(lro_desc->parent)->gso_size = lro_desc->mss; ++ ++ if (lro_desc->vgrp) { ++ if (test_bit(LRO_F_NAPI, &lro_mgr->features)) ++ vlan_hwaccel_receive_skb(lro_desc->parent, ++ lro_desc->vgrp, ++ lro_desc->vlan_tag); ++ else ++ vlan_hwaccel_rx(lro_desc->parent, ++ lro_desc->vgrp, ++ lro_desc->vlan_tag); ++ ++ } else { ++ if (test_bit(LRO_F_NAPI, &lro_mgr->features)) ++ netif_receive_skb(lro_desc->parent); ++ else ++ netif_rx(lro_desc->parent); ++ } ++ ++ LRO_INC_STATS(lro_mgr, flushed); ++ lro_clear_desc(lro_desc); ++} ++ ++static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr, ++ struct skb_frag_struct *frags, ++ int len, int true_size, ++ void *mac_hdr, ++ int hlen, __wsum sum, ++ u32 ip_summed) ++{ ++ struct sk_buff *skb; ++ struct skb_frag_struct *skb_frags; ++ int data_len = len; ++ int hdr_len = min(len, hlen); ++ ++ skb = netdev_alloc_skb(lro_mgr->dev, hlen); ++ if (!skb) ++ return NULL; ++ ++ skb->len = len; ++ skb->data_len = len - hdr_len; ++ skb->truesize += true_size; ++ skb->tail += hdr_len; ++ ++ memcpy(skb->data, mac_hdr, hdr_len); ++ ++ if (skb->data_len) { ++ skb_frags = skb_shinfo(skb)->frags; ++ while (data_len > 0) { ++ *skb_frags = *frags; ++ data_len -= frags->size; ++ skb_frags++; ++ frags++; ++ skb_shinfo(skb)->nr_frags++; ++ } ++ skb_shinfo(skb)->frags[0].page_offset += hdr_len; ++ skb_shinfo(skb)->frags[0].size -= hdr_len; ++ } else { ++ put_page(frags[0].page); ++ } ++ ++ ++ skb->ip_summed = ip_summed; ++ skb->csum = sum; ++ skb->protocol = eth_type_trans(skb, lro_mgr->dev); ++ return skb; ++} ++ ++static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, ++ struct skb_frag_struct *frags, ++ int len, int true_size, ++ struct vlan_group *vgrp, ++ u16 vlan_tag, void *priv, __wsum sum) ++{ ++ struct net_lro_desc *lro_desc; ++ struct iphdr *iph; ++ struct tcphdr *tcph; ++ struct sk_buff *skb; ++ u64 flags; ++ void *mac_hdr; ++ int mac_hdr_len; ++ int hdr_len = LRO_MAX_PG_HLEN; ++ int vlan_hdr_len = 0; ++ u8 pad_bytes; ++ ++ if (!lro_mgr->get_frag_header ++ || lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, ++ (void *)&tcph, &flags, priv)) { ++ mac_hdr = page_address(frags->page) + frags->page_offset; ++ goto out1; ++ } ++ ++ if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) ++ goto out1; ++ ++ hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr); ++ mac_hdr_len = (int)((void *)(iph) - mac_hdr); ++ ++ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); ++ if (!lro_desc) ++ goto out1; ++ ++ pad_bytes = len - (ntohs(iph->tot_len) + mac_hdr_len); ++ if (!TCP_PAYLOAD_LENGTH(iph, tcph) && pad_bytes) { ++ len -= pad_bytes; /* trim the packet */ ++ frags[0].size -= pad_bytes; ++ true_size -= pad_bytes; ++ } ++ ++ if (!lro_desc->active) { /* start new lro session */ ++ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL)) ++ goto out1; ++ ++ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, ++ hdr_len, 0, lro_mgr->ip_summed_aggr); ++ if (!skb) ++ goto out; ++ ++ if ((skb->protocol == htons(ETH_P_8021Q)) ++ && !test_bit(LRO_F_EXTRACT_VLAN_ID, &lro_mgr->features)) ++ vlan_hdr_len = VLAN_HLEN; ++ ++ iph = (void *)(skb->data + vlan_hdr_len); ++ tcph = (void *)((u8 *)skb->data + vlan_hdr_len ++ + IP_HDR_LEN(iph)); ++ ++ lro_init_desc(lro_desc, skb, iph, tcph, vlan_tag, vgrp); ++ LRO_INC_STATS(lro_mgr, aggregated); ++ return 0; ++ } ++ ++ if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) ++ goto out2; ++ ++ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc)) ++ goto out2; ++ ++ lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph); ++ LRO_INC_STATS(lro_mgr, aggregated); ++ ++ if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) || ++ lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu)) ++ lro_flush(lro_mgr, lro_desc); ++ ++ return NULL; ++ ++out2: /* send aggregated packets to the stack */ ++ lro_flush(lro_mgr, lro_desc); ++ ++out1: /* Original packet has to be posted to the stack */ ++ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, ++ hdr_len, sum, lro_mgr->ip_summed); ++out: ++ return skb; ++} ++ ++void lro_receive_frags_compat(struct net_lro_mgr *lro_mgr, ++ struct skb_frag_struct *frags, ++ int len, int true_size, void *priv, __wsum sum) ++{ ++ struct sk_buff *skb; ++ ++ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, NULL, 0, ++ priv, sum); ++ if (!skb) ++ return; ++ ++ if (test_bit(LRO_F_NAPI, &lro_mgr->features)) ++ netif_receive_skb(skb); ++ else ++ netif_rx(skb); ++} ++ ++void lro_vlan_hwaccel_receive_frags_compat(struct net_lro_mgr *lro_mgr, ++ struct skb_frag_struct *frags, ++ int len, int true_size, ++ struct vlan_group *vgrp, ++ u16 vlan_tag, void *priv, __wsum sum) ++{ ++ struct sk_buff *skb; ++ ++ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, vgrp, ++ vlan_tag, priv, sum); ++ if (!skb) ++ return; ++ ++ if (test_bit(LRO_F_NAPI, &lro_mgr->features)) ++ vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag); ++ else ++ vlan_hwaccel_rx(skb, vgrp, vlan_tag); ++} ++ ++void lro_flush_all_compat(struct net_lro_mgr *lro_mgr) ++{ ++ int i; ++ struct net_lro_desc *lro_desc = lro_mgr->lro_arr; ++ ++ for (i = 0; i < lro_mgr->max_desc; i++) { ++ if (lro_desc[i].active) ++ lro_flush(lro_mgr, &lro_desc[i]); ++ } ++} ++#endif /* INET_LRO backport */ ++ ++#ifndef TX_MQ ++struct net_device *alloc_etherdev_mq_compat(int sizeof_priv, ++ unsigned int queue_count) ++{ ++ return alloc_etherdev(sizeof_priv); ++} ++ ++void netif_wake_subqueue_compat(struct net_device *dev, u16 queue_index) ++{ ++ netif_wake_queue(dev); ++} ++ ++void netif_stop_subqueue_compat(struct net_device *dev, u16 queue_index) ++{ ++ netif_stop_queue(dev); ++} ++ ++int __netif_subqueue_stopped_compat(const struct net_device *dev, ++ u16 queue_index) ++{ ++ return netif_queue_stopped(dev); ++} ++ ++u16 skb_get_queue_mapping_compat(const struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++void netif_set_real_num_tx_queues_compat(struct net_device *dev, ++ unsigned int txq) ++{ ++ return; ++} ++ ++u16 skb_tx_hash_compat(const struct net_device *dev, ++ const struct sk_buff *skb) ++{ ++ return 0; ++} ++#endif +diff --git a/drivers/net/benet/be_compat.h b/drivers/net/benet/be_compat.h +new file mode 100644 +index 0000000..8ceecc8 +--- /dev/null ++++ b/drivers/net/benet/be_compat.h +@@ -0,0 +1,621 @@ ++/* ++ * Copyright (C) 2005 - 2011 Emulex ++ * 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@emulex.com ++ * ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 ++ */ ++ ++#ifndef BE_COMPAT_H ++#define BE_COMPAT_H ++ ++/****************** RHEL5 and SLES10 backport ***************************/ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) ++ ++#ifndef upper_32_bits ++#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) ++#endif ++ ++#ifndef CHECKSUM_PARTIAL ++#define CHECKSUM_PARTIAL CHECKSUM_HW ++#define CHECKSUM_COMPLETE CHECKSUM_HW ++#endif ++ ++#if !defined(ip_hdr) ++#define ip_hdr(skb) (skb->nh.iph) ++#define ipv6_hdr(skb) (skb->nh.ipv6h) ++#endif ++ ++#if !defined(__packed) ++#define __packed __attribute__ ((packed)) ++#endif ++ ++#if !defined(RHEL_MINOR) ++/* Only for RH5U1 (Maui) and SLES10 NIC driver */ ++enum { ++ false = 0, ++ true = 1 ++}; ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) ++/* Only for RH5U1 (Maui) NIC driver */ ++static inline __attribute__((const)) ++int __ilog2_u32(u32 n) ++{ ++ return fls(n) - 1; ++} ++#endif ++#endif ++ ++#define ETH_FCS_LEN 4 ++#define bool u8 ++#ifndef PTR_ALIGN ++#define PTR_ALIGN(p, a) ((typeof(p)) \ ++ ALIGN((unsigned long)(p), (a))) ++#endif ++#define list_first_entry(ptr, type, member) \ ++ list_entry((ptr)->next, type, member) ++ ++#if (defined(RHEL_MINOR) && RHEL_MINOR < 6) || \ ++ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16) ++#define DEFINE_PCI_DEVICE_TABLE(_table) struct pci_device_id _table[] \ ++ __devinitdata ++#endif ++ ++/* Backport of request_irq */ ++typedef irqreturn_t(*backport_irq_handler_t) (int, void *); ++static inline int ++backport_request_irq(unsigned int irq, irqreturn_t(*handler) (int, void *), ++ unsigned long flags, const char *dev_name, void *dev_id) ++{ ++ return request_irq(irq, ++ (irqreturn_t(*) (int, void *, struct pt_regs *))handler, ++ flags, dev_name, dev_id); ++} ++#define request_irq backport_request_irq ++ ++#endif /*** RHEL5 and SLES10 backport ***/ ++ ++#if !defined(__packed) ++#define __packed __attribute__ ((packed)) ++#endif ++ ++/****************** SLES10 only backport ***************************/ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) ++ ++#include <linux/tifm.h> ++ ++#define FIELD_SIZEOF(t, f) (sizeof(((t *)0)->f)) ++#define IRQF_SHARED SA_SHIRQ ++#define CHECKSUM_PARTIAL CHECKSUM_HW ++#define CHECKSUM_COMPLETE CHECKSUM_HW ++#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) ++#define NETIF_F_IPV6_CSUM NETIF_F_IP_CSUM ++#define NETIF_F_TSO6 NETIF_F_TSO ++ ++ ++static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, ++ unsigned int length) ++{ ++ /* 16 == NET_PAD_SKB */ ++ struct sk_buff *skb; ++ skb = alloc_skb(length + 16, GFP_ATOMIC); ++ if (likely(skb != NULL)) { ++ skb_reserve(skb, 16); ++ skb->dev = dev; ++ } ++ return skb; ++} ++ ++#define PCI_SAVE_STATE(x) ++ ++#else /* SLES10 only backport */ ++ ++#define PCI_SAVE_STATE(x) pci_save_state(x) ++ ++#endif /* SLES10 only backport */ ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31) ++#define netdev_tx_t int ++#endif ++ ++#ifndef VLAN_PRIO_MASK ++#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ ++#define VLAN_PRIO_SHIFT 13 ++#endif ++ ++/* ++ * Backport of netdev ops struct ++ */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) ++struct net_device_ops { ++ int (*ndo_init)(struct net_device *dev); ++ void (*ndo_uninit)(struct net_device *dev); ++ int (*ndo_open)(struct net_device *dev); ++ int (*ndo_stop)(struct net_device *dev); ++ int (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev); ++ u16 (*ndo_select_queue)(struct net_device *dev, ++ struct sk_buff *skb); ++ void (*ndo_change_rx_flags)(struct net_device *dev, int flags); ++ void (*ndo_set_rx_mode)(struct net_device *dev); ++ void (*ndo_set_multicast_list)(struct net_device *dev); ++ int (*ndo_set_mac_address)(struct net_device *dev, void *addr); ++ int (*ndo_validate_addr)(struct net_device *dev); ++ int (*ndo_do_ioctl)(struct net_device *dev, ++ struct ifreq *ifr, int cmd); ++ int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); ++ int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); ++ int (*ndo_neigh_setup)(struct net_device *dev, ++ struct neigh_parms *); ++ void (*ndo_tx_timeout) (struct net_device *dev); ++ ++ struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); ++ ++ void (*ndo_vlan_rx_register)(struct net_device *dev, ++ struct vlan_group *grp); ++ void (*ndo_vlan_rx_add_vid)(struct net_device *dev, ++ unsigned short vid); ++ void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, ++ unsigned short vid); ++#ifdef CONFIG_NET_POLL_CONTROLLER ++#define HAVE_NETDEV_POLL ++ void (*ndo_poll_controller)(struct net_device *dev); ++#endif ++}; ++extern void be_netdev_ops_init(struct net_device *netdev, ++ struct net_device_ops *ops); ++extern int eth_validate_addr(struct net_device *); ++ ++#endif /* Netdev ops backport */ ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 29) ++#undef NETIF_F_GRO ++#endif ++ ++#ifdef NO_GRO ++#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 5))) ++#undef NETIF_F_GRO ++#endif ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#define HAVE_ETHTOOL_FLASH ++#endif ++ ++/* ++ * Backport of NAPI ++ */ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24) ++ ++#if defined(RHEL_MINOR) && (RHEL_MINOR > 3) ++#define RHEL_NEW_NAPI ++#endif ++ ++/* We need a new struct that has some meta data beyond rhel 5.4's napi_struct ++ * to fix rhel5.4's half-baked new napi implementation. ++ * We don't want to use rhel 5.4's broken napi_complete; so ++ * define a new be_napi_complete that executes the logic only for Rx ++ */ ++ ++#ifdef RHEL_NEW_NAPI ++#define napi_complete be_napi_complete ++typedef struct napi_struct rhel_napi_struct; ++#endif ++#define napi_struct be_napi_struct ++#define napi_gro_frags(napi) napi_gro_frags((rhel_napi_struct *) napi) ++#define vlan_gro_frags(napi, vlan_grp, vid)\ ++ vlan_gro_frags((rhel_napi_struct *) napi, vlan_grp, vid) ++#define napi_get_frags(napi) napi_get_frags((rhel_napi_struct *) napi) ++ ++struct napi_struct { ++#ifdef RHEL_NEW_NAPI ++ rhel_napi_struct napi; /* must be the first member */ ++#endif ++ struct net_device *dev; ++ int (*poll) (struct napi_struct *napi, int budget); ++ bool rx; ++}; ++ ++static inline void napi_complete(struct napi_struct *napi) ++{ ++#ifdef NETIF_F_GRO ++ napi_gro_flush((rhel_napi_struct *)napi); ++#endif ++ netif_rx_complete(napi->dev); ++} ++ ++static inline void napi_schedule(struct napi_struct *napi) ++{ ++ netif_rx_schedule(napi->dev); ++} ++ ++static inline void napi_enable(struct napi_struct *napi) ++{ ++ netif_poll_enable(napi->dev); ++} ++ ++static inline void napi_disable(struct napi_struct *napi) ++{ ++ netif_poll_disable(napi->dev); ++} ++ ++#if (defined(RHEL_MINOR) && RHEL_MINOR < 6) || \ ++ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16) ++static inline void vlan_group_set_device(struct vlan_group *vg, ++ u16 vlan_id, ++ struct net_device *dev) ++{ ++ struct net_device **array; ++ if (!vg) ++ return; ++ array = vg->vlan_devices; ++ array[vlan_id] = dev; ++} ++#endif ++ ++#endif /* New NAPI backport */ ++ ++extern int be_netif_napi_add(struct net_device *netdev, ++ struct napi_struct *napi, ++ int (*poll) (struct napi_struct *, int), int weight); ++extern void be_netif_napi_del(struct net_device *netdev); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) ++#define HAVE_SIMULATED_MULTI_NAPI ++#endif ++ ++/************** Backport of Delayed work queues interface ****************/ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ++#if (defined(RHEL_MINOR) && RHEL_MINOR < 6) || \ ++ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16) ++struct delayed_work { ++ struct work_struct work; ++}; ++#endif ++ ++#define INIT_DELAYED_WORK(_work, _func) \ ++ INIT_WORK(&(_work)->work, _func, &(_work)->work) ++ ++static inline int backport_cancel_delayed_work_sync(struct delayed_work *work) ++{ ++ cancel_rearming_delayed_work(&work->work); ++ return 0; ++} ++#define cancel_delayed_work_sync backport_cancel_delayed_work_sync ++ ++static inline int backport_schedule_delayed_work(struct delayed_work *work, ++ unsigned long delay) ++{ ++ if (unlikely(!delay)) ++ return schedule_work(&work->work); ++ else ++ return schedule_delayed_work(&work->work, delay); ++} ++#define schedule_delayed_work backport_schedule_delayed_work ++#endif /* backport delayed workqueue */ ++ ++ ++/************** Backport of INET_LRO **********************************/ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) ++ ++#include <linux/inet_lro.h> ++ ++#else ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) ++ ++#if defined(RHEL_MINOR) && RHEL_MINOR < 6 ++typedef __u16 __bitwise __sum16; ++typedef __u32 __bitwise __wsum; ++#endif ++ ++#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 5) && (RHEL_MINOR <= 3)) || \ ++ (!defined(RHEL_MINOR))) ++static inline __wsum csum_unfold(__sum16 n) ++{ ++ return (__force __wsum)n; ++} ++#endif ++ ++#endif ++ ++#define lro_flush_all lro_flush_all_compat ++#define lro_vlan_hwaccel_receive_frags lro_vlan_hwaccel_receive_frags_compat ++#define lro_receive_frags lro_receive_frags_compat ++ ++struct net_lro_stats { ++ unsigned long aggregated; ++ unsigned long flushed; ++ unsigned long no_desc; ++}; ++ ++struct net_lro_desc { ++ struct sk_buff *parent; ++ struct sk_buff *last_skb; ++ struct skb_frag_struct *next_frag; ++ struct iphdr *iph; ++ struct tcphdr *tcph; ++ struct vlan_group *vgrp; ++ __wsum data_csum; ++ u32 tcp_rcv_tsecr; ++ u32 tcp_rcv_tsval; ++ u32 tcp_ack; ++ u32 tcp_next_seq; ++ u32 skb_tot_frags_len; ++ u32 ack_cnt; ++ u16 ip_tot_len; ++ u16 tcp_saw_tstamp; /* timestamps enabled */ ++ u16 tcp_window; ++ u16 vlan_tag; ++ int pkt_aggr_cnt; /* counts aggregated packets */ ++ int vlan_packet; ++ int mss; ++ int active; ++}; ++ ++struct net_lro_mgr { ++ struct net_device *dev; ++ struct net_lro_stats stats; ++ ++ /* LRO features */ ++ unsigned long features; ++#define LRO_F_NAPI 1 /* Pass packets to stack via NAPI */ ++#define LRO_F_EXTRACT_VLAN_ID 2 /* Set flag if VLAN IDs are extracted ++ from received packets and eth protocol ++ is still ETH_P_8021Q */ ++ ++ u32 ip_summed; /* Set in non generated SKBs in page mode */ ++ u32 ip_summed_aggr; /* Set in aggregated SKBs: CHECKSUM_UNNECESSARY ++ * or CHECKSUM_NONE */ ++ ++ int max_desc; /* Max number of LRO descriptors */ ++ int max_aggr; /* Max number of LRO packets to be aggregated */ ++ ++ struct net_lro_desc *lro_arr; /* Array of LRO descriptors */ ++ ++ /* Optimized driver functions ++ * get_skb_header: returns tcp and ip header for packet in SKB ++ */ ++ int (*get_skb_header)(struct sk_buff *skb, void **ip_hdr, ++ void **tcpudp_hdr, u64 *hdr_flags, void *priv); ++ ++ /* hdr_flags: */ ++#define LRO_IPV4 1 /* ip_hdr is IPv4 header */ ++#define LRO_TCP 2 /* tcpudp_hdr is TCP header */ ++ ++ /* ++ * get_frag_header: returns mac, tcp and ip header for packet in SKB ++ * ++ * @hdr_flags: Indicate what kind of LRO has to be done ++ * (IPv4/IPv6/TCP/UDP) ++ */ ++ int (*get_frag_header)(struct skb_frag_struct *frag, void **mac_hdr, ++ void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags, ++ void *priv); ++}; ++ ++extern void lro_receive_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, ++ void *priv); ++ ++extern void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr, ++ struct sk_buff *skb, struct vlan_group *vgrp, ++ u16 vlan_tag, void *priv); ++ ++/* This functions aggregate fragments and generate SKBs do pass ++ * the packets to the stack. ++ * ++ * @lro_mgr: LRO manager to use ++ * @frags: Fragment to be processed. Must contain entire header in first ++ * element. ++ * @len: Length of received data ++ * @true_size: Actual size of memory the fragment is consuming ++ * @priv: Private data that may be used by driver functions ++ * (for example get_tcp_ip_hdr) ++ */ ++extern void lro_receive_frags_compat(struct net_lro_mgr *lro_mgr, ++ struct skb_frag_struct *frags, int len, int true_size, ++ void *priv, __wsum sum); ++ ++extern void lro_vlan_hwaccel_receive_frags_compat(struct net_lro_mgr *lro_mgr, ++ struct skb_frag_struct *frags, int len, int true_size, ++ struct vlan_group *vgrp, u16 vlan_tag, void *priv, ++ __wsum sum); ++ ++/* Forward all aggregated SKBs held by lro_mgr to network stack */ ++extern void lro_flush_all_compat(struct net_lro_mgr *lro_mgr); ++ ++extern void lro_flush_pkt(struct net_lro_mgr *lro_mgr, struct iphdr *iph, ++ struct tcphdr *tcph); ++#endif /* backport of inet_lro */ ++ ++#ifndef ETHTOOL_FLASH_MAX_FILENAME ++#define ETHTOOL_FLASH_MAX_FILENAME 128 ++#endif ++ ++#if defined(CONFIG_XEN) && !defined(NETIF_F_GRO) ++#define BE_INIT_FRAGS_PER_FRAME (u32) 1 ++#else ++#define BE_INIT_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS)) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) ++#ifdef CONFIG_PCI_IOV ++#if (!(defined(RHEL_MAJOR) && (RHEL_MAJOR == 5) && (RHEL_MINOR == 6))) ++#undef CONFIG_PCI_IOV ++#endif ++#endif ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) ++#define dev_to_node(dev) -1 ++#endif ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) ++#if (!(defined(RHEL_MAJOR) && (RHEL_MAJOR == 5) && (RHEL_MINOR > 6))) ++static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length) ++{ ++ struct sk_buff *skb = netdev_alloc_skb(dev, length + NET_IP_ALIGN); ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++#endif ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) ++#ifndef netif_set_gso_max_size ++#define netif_set_gso_max_size(netdev, size) do {} while (0) ++#endif ++#endif ++ ++#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) ++#if defined(RHEL_MINOR) && (RHEL_MINOR <= 4) ++static inline int skb_is_gso_v6(const struct sk_buff *skb) ++{ ++ return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6; ++} ++#endif ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++static inline int skb_is_gso_v6(const struct sk_buff *skb) ++{ ++ return (ip_hdr(skb)->version == 6); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 6))) ++#define HAVE_SRIOV_CONFIG ++#endif ++#endif ++ ++#ifndef NETIF_F_VLAN_SG ++#define NETIF_F_VLAN_SG NETIF_F_SG ++#endif ++ ++#ifndef NETIF_F_VLAN_CSUM ++#define NETIF_F_VLAN_CSUM NETIF_F_HW_CSUM ++#endif ++ ++#ifndef NETIF_F_VLAN_TSO ++#define NETIF_F_VLAN_TSO NETIF_F_TSO ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)) ++#define vlan_features features ++#endif ++ ++#ifndef DEFINE_DMA_UNMAP_ADDR ++#define DEFINE_DMA_UNMAP_ADDR(bus) dma_addr_t bus ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) ++ ++#ifndef netdev_mc_count ++#define netdev_mc_count(nd) (nd->mc_count) ++#endif ++ ++#ifndef netdev_hw_addr ++#define netdev_hw_addr dev_mc_list ++#endif ++ ++#ifndef netdev_for_each_mc_addr ++#define netdev_for_each_mc_addr(ha, nd) \ ++ for (ha = (nd)->mc_list; ha; ha = ha->next) ++#endif ++ ++#define DMI_ADDR dmi_addr ++#else ++#define DMI_ADDR addr ++#endif ++ ++#ifndef VLAN_GROUP_ARRAY_LEN ++#define VLAN_GROUP_ARRAY_LEN VLAN_N_VID ++#endif ++/**************************** Multi TXQ Support ******************************/ ++ ++/* Supported only in RHEL6 and SL11.1 (barring one execption) */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#define MQ_TX ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) ++#define alloc_etherdev_mq(sz, cnt) alloc_etherdev(sz) ++#define skb_get_queue_mapping(skb) 0 ++#define skb_tx_hash(dev, skb) 0 ++#define netif_set_real_num_tx_queues(dev, txq) do {} while(0) ++#define netif_wake_subqueue(dev, idx) netif_wake_queue(dev) ++#define netif_stop_subqueue(dev, idx) netif_stop_queue(dev) ++#define __netif_subqueue_stopped(dev, idx) netif_queue_stopped(dev) ++#endif /* < 2.6.27 */ ++ ++#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && \ ++ (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32))) ++#define skb_tx_hash(dev, skb) 0 ++#define netif_set_real_num_tx_queues(dev, txq) do {} while(0) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#define netif_set_real_num_tx_queues be_set_real_num_tx_queues ++static inline void be_set_real_num_tx_queues(struct net_device *dev, ++ unsigned int txq) ++{ ++ dev->real_num_tx_queues = txq; ++} ++#endif ++ ++#include <linux/if_vlan.h> ++static inline void be_reset_skb_tx_vlan(struct sk_buff *skb) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) ++ skb->vlan_tci = 0; ++#else ++ struct vlan_skb_tx_cookie *cookie; ++ ++ cookie = VLAN_TX_SKB_CB(skb); ++ cookie->magic = 0; ++#endif ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++static inline void skb_set_network_header(struct sk_buff *skb, const int offset) ++{ ++ skb->nh.raw = skb->data + offset; ++} ++#endif ++ ++static inline struct sk_buff *be_vlan_put_tag(struct sk_buff *skb, ++ unsigned short vlan_tag) ++{ ++ struct sk_buff *new_skb = __vlan_put_tag(skb, vlan_tag); ++ /* On kernel versions < 2.6.27 the __vlan_put_tag() function ++ * distorts the network layer hdr pointer in the skb which ++ * affects the detection of UDP/TCP packets down the line in ++ * wrb_fill_hdr().This work-around sets it right. ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)) ++ skb_set_network_header(new_skb, VLAN_ETH_HLEN); ++#endif ++ return new_skb; ++} ++ ++#ifndef ACCESS_ONCE ++#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) ++#endif ++ ++#endif /* BE_COMPAT_H */ +diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c +index f0fd95b..37bad99 100644 +--- a/drivers/net/benet/be_ethtool.c ++++ b/drivers/net/benet/be_ethtool.c +@@ -1,18 +1,18 @@ + /* +- * Copyright (C) 2005 - 2009 ServerEngines ++ * Copyright (C) 2005 - 2011 Emulex + * 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 ++ * 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 ++ * linux-drivers@emulex.com + * +- * ServerEngines +- * 209 N. Fair Oaks Ave +- * Sunnyvale, CA 94085 ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 + */ + + #include "be.h" +@@ -26,21 +26,19 @@ struct be_ethtool_stat { + int offset; + }; + +-enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT}; ++enum {NETSTAT, DRVSTAT_TX, DRVSTAT_RX, DRVSTAT}; + #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \ + offsetof(_struct, field) +-#define NETSTAT_INFO(field) #field, NETSTAT,\ ++#define NETSTAT_INFO(field) #field, NETSTAT,\ + FIELDINFO(struct net_device_stats,\ + field) +-#define DRVSTAT_INFO(field) #field, DRVSTAT,\ +- FIELDINFO(struct be_drvr_stats, field) +-#define MISCSTAT_INFO(field) #field, MISCSTAT,\ +- FIELDINFO(struct be_rxf_stats, field) +-#define PORTSTAT_INFO(field) #field, PORTSTAT,\ +- FIELDINFO(struct be_port_rxf_stats, \ ++#define DRVSTAT_TX_INFO(field) #field, DRVSTAT_TX,\ ++ FIELDINFO(struct be_tx_stats, field) ++#define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\ ++ FIELDINFO(struct be_rx_stats, field) ++#define DRVSTAT_INFO(field) #field, DRVSTAT,\ ++ FIELDINFO(struct be_drv_stats, \ + field) +-#define ERXSTAT_INFO(field) #field, ERXSTAT,\ +- FIELDINFO(struct be_erx_stats, field) + + static const struct be_ethtool_stat et_stats[] = { + {NETSTAT_INFO(rx_packets)}, +@@ -51,70 +49,131 @@ static const struct be_ethtool_stat et_stats[] = { + {NETSTAT_INFO(tx_errors)}, + {NETSTAT_INFO(rx_dropped)}, + {NETSTAT_INFO(tx_dropped)}, +- {DRVSTAT_INFO(be_tx_reqs)}, +- {DRVSTAT_INFO(be_tx_stops)}, +- {DRVSTAT_INFO(be_fwd_reqs)}, +- {DRVSTAT_INFO(be_tx_wrbs)}, +- {DRVSTAT_INFO(be_polls)}, + {DRVSTAT_INFO(be_tx_events)}, +- {DRVSTAT_INFO(be_rx_events)}, +- {DRVSTAT_INFO(be_tx_compl)}, +- {DRVSTAT_INFO(be_rx_compl)}, +- {DRVSTAT_INFO(be_ethrx_post_fail)}, +- {DRVSTAT_INFO(be_802_3_dropped_frames)}, +- {DRVSTAT_INFO(be_802_3_malformed_frames)}, +- {DRVSTAT_INFO(be_tx_rate)}, +- {DRVSTAT_INFO(be_rx_rate)}, +- {PORTSTAT_INFO(rx_unicast_frames)}, +- {PORTSTAT_INFO(rx_multicast_frames)}, +- {PORTSTAT_INFO(rx_broadcast_frames)}, +- {PORTSTAT_INFO(rx_crc_errors)}, +- {PORTSTAT_INFO(rx_alignment_symbol_errors)}, +- {PORTSTAT_INFO(rx_pause_frames)}, +- {PORTSTAT_INFO(rx_control_frames)}, +- {PORTSTAT_INFO(rx_in_range_errors)}, +- {PORTSTAT_INFO(rx_out_range_errors)}, +- {PORTSTAT_INFO(rx_frame_too_long)}, +- {PORTSTAT_INFO(rx_address_match_errors)}, +- {PORTSTAT_INFO(rx_vlan_mismatch)}, +- {PORTSTAT_INFO(rx_dropped_too_small)}, +- {PORTSTAT_INFO(rx_dropped_too_short)}, +- {PORTSTAT_INFO(rx_dropped_header_too_small)}, +- {PORTSTAT_INFO(rx_dropped_tcp_length)}, +- {PORTSTAT_INFO(rx_dropped_runt)}, +- {PORTSTAT_INFO(rx_fifo_overflow)}, +- {PORTSTAT_INFO(rx_input_fifo_overflow)}, +- {PORTSTAT_INFO(rx_ip_checksum_errs)}, +- {PORTSTAT_INFO(rx_tcp_checksum_errs)}, +- {PORTSTAT_INFO(rx_udp_checksum_errs)}, +- {PORTSTAT_INFO(rx_non_rss_packets)}, +- {PORTSTAT_INFO(rx_ipv4_packets)}, +- {PORTSTAT_INFO(rx_ipv6_packets)}, +- {PORTSTAT_INFO(tx_unicastframes)}, +- {PORTSTAT_INFO(tx_multicastframes)}, +- {PORTSTAT_INFO(tx_broadcastframes)}, +- {PORTSTAT_INFO(tx_pauseframes)}, +- {PORTSTAT_INFO(tx_controlframes)}, +- {MISCSTAT_INFO(rx_drops_no_pbuf)}, +- {MISCSTAT_INFO(rx_drops_no_txpb)}, +- {MISCSTAT_INFO(rx_drops_no_erx_descr)}, +- {MISCSTAT_INFO(rx_drops_no_tpre_descr)}, +- {MISCSTAT_INFO(rx_drops_too_many_frags)}, +- {MISCSTAT_INFO(rx_drops_invalid_ring)}, +- {MISCSTAT_INFO(forwarded_packets)}, +- {MISCSTAT_INFO(rx_drops_mtu)}, +- {ERXSTAT_INFO(rx_drops_no_fragments)}, ++ {DRVSTAT_INFO(rx_crc_errors)}, ++ {DRVSTAT_INFO(rx_alignment_symbol_errors)}, ++ {DRVSTAT_INFO(rx_pause_frames)}, ++ {DRVSTAT_INFO(rx_control_frames)}, ++ {DRVSTAT_INFO(rx_in_range_errors)}, ++ {DRVSTAT_INFO(rx_out_range_errors)}, ++ {DRVSTAT_INFO(rx_frame_too_long)}, ++ {DRVSTAT_INFO(rx_address_match_errors)}, ++ {DRVSTAT_INFO(rx_dropped_too_small)}, ++ {DRVSTAT_INFO(rx_dropped_too_short)}, ++ {DRVSTAT_INFO(rx_dropped_header_too_small)}, ++ {DRVSTAT_INFO(rx_dropped_tcp_length)}, ++ {DRVSTAT_INFO(rx_dropped_runt)}, ++ {DRVSTAT_INFO(rxpp_fifo_overflow_drop)}, ++ {DRVSTAT_INFO(rx_input_fifo_overflow_drop)}, ++ {DRVSTAT_INFO(rx_ip_checksum_errs)}, ++ {DRVSTAT_INFO(rx_tcp_checksum_errs)}, ++ {DRVSTAT_INFO(rx_udp_checksum_errs)}, ++ {DRVSTAT_INFO(rx_switched_unicast_packets)}, ++ {DRVSTAT_INFO(rx_switched_multicast_packets)}, ++ {DRVSTAT_INFO(rx_switched_broadcast_packets)}, ++ {DRVSTAT_INFO(tx_pauseframes)}, ++ {DRVSTAT_INFO(tx_controlframes)}, ++ {DRVSTAT_INFO(rx_priority_pause_frames)}, ++ {DRVSTAT_INFO(pmem_fifo_overflow_drop)}, ++ {DRVSTAT_INFO(jabber_events)}, ++ {DRVSTAT_INFO(rx_drops_no_pbuf)}, ++ {DRVSTAT_INFO(rx_drops_no_txpb)}, ++ {DRVSTAT_INFO(rx_drops_no_erx_descr)}, ++ {DRVSTAT_INFO(rx_drops_no_tpre_descr)}, ++ {DRVSTAT_INFO(rx_drops_too_many_frags)}, ++ {DRVSTAT_INFO(rx_drops_invalid_ring)}, ++ {DRVSTAT_INFO(forwarded_packets)}, ++ {DRVSTAT_INFO(rx_drops_mtu)}, ++ {DRVSTAT_INFO(eth_red_drops)}, ++ {DRVSTAT_INFO(be_on_die_temperature)} + }; + #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) + ++/* Stats related to multi RX queues */ ++static const struct be_ethtool_stat et_rx_stats[] = { ++ {DRVSTAT_RX_INFO(rx_bytes)}, ++ {DRVSTAT_RX_INFO(rx_pkts)}, ++ {DRVSTAT_RX_INFO(rx_rate)}, ++ {DRVSTAT_RX_INFO(rx_polls)}, ++ {DRVSTAT_RX_INFO(rx_events)}, ++ {DRVSTAT_RX_INFO(rx_compl)}, ++ {DRVSTAT_RX_INFO(rx_mcast_pkts)}, ++ {DRVSTAT_RX_INFO(rx_post_fail)}, ++ {DRVSTAT_RX_INFO(rx_drops_no_frags)} ++}; ++#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats)) ++ ++/* Stats related to multi TX queues */ ++static const struct be_ethtool_stat et_tx_stats[] = { ++ {DRVSTAT_TX_INFO(be_tx_rate)}, ++ {DRVSTAT_TX_INFO(be_tx_reqs)}, ++ {DRVSTAT_TX_INFO(be_tx_wrbs)}, ++ {DRVSTAT_TX_INFO(be_tx_stops)}, ++ {DRVSTAT_TX_INFO(be_tx_compl)}, ++ {DRVSTAT_TX_INFO(be_ipv6_ext_hdr_tx_drop)} ++}; ++#define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats)) ++ ++static const char et_self_tests[][ETH_GSTRING_LEN] = { ++ "MAC Loopback test", ++ "PHY Loopback test", ++ "External Loopback test", ++ "DDR DMA test", ++ "Link test" ++}; ++ ++#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests) ++#define BE_MAC_LOOPBACK 0x0 ++#define BE_PHY_LOOPBACK 0x1 ++#define BE_ONE_PORT_EXT_LOOPBACK 0x2 ++#define BE_NO_LOOPBACK 0xff ++ ++/* MAC speed valid values */ ++#define SPEED_DEFAULT 0x0 ++#define SPEED_FORCED_10GB 0x1 ++#define SPEED_FORCED_1GB 0x2 ++#define SPEED_AUTONEG_10GB 0x3 ++#define SPEED_AUTONEG_1GB 0x4 ++#define SPEED_AUTONEG_100MB 0x5 ++#define SPEED_AUTONEG_10GB_1GB 0x6 ++#define SPEED_AUTONEG_10GB_1GB_100MB 0x7 ++#define SPEED_AUTONEG_1GB_100MB 0x8 ++#define SPEED_AUTONEG_10MB 0x9 ++#define SPEED_AUTONEG_1GB_100MB_10MB 0xa ++#define SPEED_AUTONEG_100MB_10MB 0xb ++#define SPEED_FORCED_100MB 0xc ++#define SPEED_FORCED_10MB 0xd ++ ++ ++ + static void + be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) + { + struct be_adapter *adapter = netdev_priv(netdev); ++ int len; ++ char fw_on_flash[FW_VER_LEN]; ++ ++ memset(fw_on_flash, 0 , sizeof(fw_on_flash)); ++ ++ be_cmd_get_fw_ver(adapter, adapter->fw_ver, ++ fw_on_flash); + + strcpy(drvinfo->driver, DRV_NAME); + strcpy(drvinfo->version, DRV_VER); ++ + strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN); ++ if (memcmp(adapter->fw_ver, fw_on_flash, ++ FW_VER_LEN) != 0) { ++ len = strlen(drvinfo->fw_version); ++ strncpy(drvinfo->fw_version+len, " [", ++ FW_VER_LEN-len-1); ++ len = strlen(drvinfo->fw_version); ++ strncpy(drvinfo->fw_version+len, fw_on_flash, ++ FW_VER_LEN-len-1); ++ len = strlen(drvinfo->fw_version); ++ strncpy(drvinfo->fw_version+len, "]", FW_VER_LEN-len-1); ++ } ++ + strcpy(drvinfo->bus_info, pci_name(adapter->pdev)); + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; +@@ -122,12 +181,37 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) + } + + static int ++be_get_reg_len(struct net_device *netdev) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ u32 log_size = 0; ++ ++ if (be_physfn(adapter)) ++ be_cmd_get_reg_len(adapter, &log_size); ++ ++ return log_size; ++} ++ ++static void ++be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ if (be_physfn(adapter)) { ++ memset(buf, 0, regs->len); ++ be_cmd_get_regs(adapter, regs->len, buf); ++ } ++} ++ ++static int + be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *rx_eq = &adapter->rx_eq; ++ struct be_eq_obj *rx_eq = &adapter->rx_obj[0].rx_eq; + struct be_eq_obj *tx_eq = &adapter->tx_eq; + ++ coalesce->rx_max_coalesced_frames = adapter->max_rx_coal; ++ + coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; + coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd; + coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd; +@@ -149,25 +233,52 @@ static int + be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *rx_eq = &adapter->rx_eq; ++ struct be_rx_obj *rxo; ++ struct be_eq_obj *rx_eq; + struct be_eq_obj *tx_eq = &adapter->tx_eq; + u32 tx_max, tx_min, tx_cur; + u32 rx_max, rx_min, rx_cur; +- int status = 0; ++ int status = 0, i; + + if (coalesce->use_adaptive_tx_coalesce == 1) + return -EINVAL; ++ adapter->max_rx_coal = coalesce->rx_max_coalesced_frames; ++ if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME) ++ adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; + +- /* if AIC is being turned on now, start with an EQD of 0 */ +- if (rx_eq->enable_aic == 0 && +- coalesce->use_adaptive_rx_coalesce == 1) { +- rx_eq->cur_eqd = 0; ++ for_all_rx_queues(adapter, rxo, i) { ++ rx_eq = &rxo->rx_eq; ++ ++ if (!rx_eq->enable_aic && coalesce->use_adaptive_rx_coalesce) ++ rx_eq->cur_eqd = 0; ++ rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce; ++ ++ rx_max = coalesce->rx_coalesce_usecs_high; ++ rx_min = coalesce->rx_coalesce_usecs_low; ++ rx_cur = coalesce->rx_coalesce_usecs; ++ ++ if (rx_eq->enable_aic) { ++ if (rx_max > BE_MAX_EQD) ++ rx_max = BE_MAX_EQD; ++ if (rx_min > rx_max) ++ rx_min = rx_max; ++ rx_eq->max_eqd = rx_max; ++ rx_eq->min_eqd = rx_min; ++ if (rx_eq->cur_eqd > rx_max) ++ rx_eq->cur_eqd = rx_max; ++ if (rx_eq->cur_eqd < rx_min) ++ rx_eq->cur_eqd = rx_min; ++ } else { ++ if (rx_cur > BE_MAX_EQD) ++ rx_cur = BE_MAX_EQD; ++ if (rx_eq->cur_eqd != rx_cur) { ++ status = be_cmd_modify_eqd(adapter, rx_eq->q.id, ++ rx_cur); ++ if (!status) ++ rx_eq->cur_eqd = rx_cur; ++ } ++ } + } +- rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce; +- +- rx_max = coalesce->rx_coalesce_usecs_high; +- rx_min = coalesce->rx_coalesce_usecs_low; +- rx_cur = coalesce->rx_coalesce_usecs; + + tx_max = coalesce->tx_coalesce_usecs_high; + tx_min = coalesce->tx_coalesce_usecs_low; +@@ -181,27 +292,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) + tx_eq->cur_eqd = tx_cur; + } + +- if (rx_eq->enable_aic) { +- if (rx_max > BE_MAX_EQD) +- rx_max = BE_MAX_EQD; +- if (rx_min > rx_max) +- rx_min = rx_max; +- rx_eq->max_eqd = rx_max; +- rx_eq->min_eqd = rx_min; +- if (rx_eq->cur_eqd > rx_max) +- rx_eq->cur_eqd = rx_max; +- if (rx_eq->cur_eqd < rx_min) +- rx_eq->cur_eqd = rx_min; +- } else { +- if (rx_cur > BE_MAX_EQD) +- rx_cur = BE_MAX_EQD; +- if (rx_eq->cur_eqd != rx_cur) { +- status = be_cmd_modify_eqd(adapter, rx_eq->q.id, +- rx_cur); +- if (!status) +- rx_eq->cur_eqd = rx_cur; +- } +- } + return 0; + } + +@@ -229,81 +319,294 @@ be_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, uint64_t *data) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats; +- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va); +- struct be_rxf_stats *rxf_stats = &hw_stats->rxf; +- struct be_port_rxf_stats *port_stats = +- &rxf_stats->port[adapter->port_num]; +- struct net_device_stats *net_stats = &adapter->stats.net_stats; +- struct be_erx_stats *erx_stats = &hw_stats->erx; ++ struct be_rx_obj *rxo; ++ struct be_tx_obj *txo; + void *p = NULL; +- int i; ++ int i, j, base; + + for (i = 0; i < ETHTOOL_STATS_NUM; i++) { + switch (et_stats[i].type) { + case NETSTAT: +- p = net_stats; ++ p = &adapter->net_stats; + break; + case DRVSTAT: +- p = drvr_stats; +- break; +- case PORTSTAT: +- p = port_stats; +- break; +- case MISCSTAT: +- p = rxf_stats; +- break; +- case ERXSTAT: /* Currently only one ERX stat is provided */ +- p = (u32 *)erx_stats + adapter->rx_obj.q.id; ++ p = &adapter->drv_stats; + break; + } + + p = (u8 *)p + et_stats[i].offset; + data[i] = (et_stats[i].size == sizeof(u64)) ? +- *(u64 *)p: *(u32 *)p; ++ *(u64 *)p:(*(u32 *)p); + } + +- return; ++ base = ETHTOOL_STATS_NUM; ++ for_all_rx_queues(adapter, rxo, j) { ++ for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) { ++ p = (u8 *)&rxo->stats + et_rx_stats[i].offset; ++ data[base + j * ETHTOOL_RXSTATS_NUM + i] = ++ (et_rx_stats[i].size == sizeof(u64)) ? ++ *(u64 *)p: *(u32 *)p; ++ } ++ } ++ ++ base = ETHTOOL_STATS_NUM + adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM; ++ for_all_tx_queues(adapter, txo, j) { ++ for (i = 0; i < ETHTOOL_TXSTATS_NUM; i++) { ++ p = (u8 *)&txo->stats + et_tx_stats[i].offset; ++ data[base + j * ETHTOOL_TXSTATS_NUM + i] = ++ (et_tx_stats[i].size == sizeof(u64)) ? ++ *(u64 *)p: *(u32 *)p; ++ } ++ } + } + + static void + be_get_stat_strings(struct net_device *netdev, uint32_t stringset, + uint8_t *data) + { +- int i; ++ struct be_adapter *adapter = netdev_priv(netdev); ++ int i, j; ++ + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ETHTOOL_STATS_NUM; i++) { + memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } ++ for (i = 0; i < adapter->num_rx_qs; i++) { ++ for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) { ++ sprintf(data, "rxq%d: %s", i, ++ et_rx_stats[j].desc); ++ data += ETH_GSTRING_LEN; ++ } ++ } ++ for (i = 0; i < adapter->num_tx_qs; i++) { ++ for (j = 0; j < ETHTOOL_TXSTATS_NUM; j++) { ++ sprintf(data, "txq%d: %s", i, ++ et_tx_stats[j].desc); ++ data += ETH_GSTRING_LEN; ++ } ++ } ++ break; ++ case ETH_SS_TEST: ++ for (i = 0; i < ETHTOOL_TESTS_NUM; i++) { ++ memcpy(data, et_self_tests[i], ETH_GSTRING_LEN); ++ data += ETH_GSTRING_LEN; ++ } + break; + } + } + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) + static int be_get_stats_count(struct net_device *netdev) + { +- return ETHTOOL_STATS_NUM; ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ return ETHTOOL_STATS_NUM + adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM ++ + adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM; + } ++static int ++be_self_test_count(struct net_device *dev) ++{ ++ return ETHTOOL_TESTS_NUM; ++} ++#else ++ ++static int be_get_sset_count(struct net_device *netdev, int stringset) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ switch (stringset) { ++ case ETH_SS_TEST: ++ return ETHTOOL_TESTS_NUM; ++ case ETH_SS_STATS: ++ return ETHTOOL_STATS_NUM + ++ adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM + ++ adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM; ++ default: ++ return -EINVAL; ++ } ++} ++#endif + + static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + { +- ecmd->speed = SPEED_10000; ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_phy_info phy_info; ++ u8 mac_speed = 0; ++ u16 link_speed = 0; ++ int link_status = LINK_DOWN; ++ int status; ++ ++ if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { ++ status = be_cmd_link_status_query(adapter, &link_status, ++ &mac_speed, &link_speed, 0); ++ ++ be_link_status_update(adapter, link_status); ++ /* link_speed is in units of 10 Mbps */ ++ if (link_speed) { ++ ecmd->speed = link_speed*10; ++ } else { ++ switch (mac_speed) { ++ case PHY_LINK_SPEED_10MBPS: ++ ecmd->speed = SPEED_10; ++ break; ++ case PHY_LINK_SPEED_100MBPS: ++ ecmd->speed = SPEED_100; ++ break; ++ case PHY_LINK_SPEED_1GBPS: ++ ecmd->speed = SPEED_1000; ++ break; ++ case PHY_LINK_SPEED_10GBPS: ++ ecmd->speed = SPEED_10000; ++ break; ++ case PHY_LINK_SPEED_ZERO: ++ ecmd->speed = 0; ++ break; ++ } ++ } ++ ++ status = be_cmd_get_phy_info(adapter, &phy_info); ++ if (!status) { ++ switch (phy_info.interface_type) { ++ case PHY_TYPE_XFP_10GB: ++ case PHY_TYPE_SFP_1GB: ++ case PHY_TYPE_SFP_PLUS_10GB: ++ ecmd->port = PORT_FIBRE; ++ break; ++ default: ++ ecmd->port = PORT_TP; ++ break; ++ } ++ ++ switch (phy_info.interface_type) { ++ case PHY_TYPE_KR_10GB: ++ case PHY_TYPE_KX4_10GB: ++ ecmd->transceiver = XCVR_INTERNAL; ++ break; ++ default: ++ ecmd->transceiver = XCVR_EXTERNAL; ++ break; ++ } ++ ++ if (phy_info.auto_speeds_supported) { ++ ecmd->supported |= SUPPORTED_Autoneg; ++ ecmd->autoneg = AUTONEG_ENABLE; ++ ecmd->advertising |= ADVERTISED_Autoneg; ++ } ++ ++ if (phy_info.misc_params & BE_PAUSE_SYM_EN) { ++ ecmd->supported |= SUPPORTED_Pause; ++ ecmd->advertising |= ADVERTISED_Pause; ++ } ++ ++ } ++ ++ /* Save for future use */ ++ adapter->link_speed = ecmd->speed; ++ adapter->port_type = ecmd->port; ++ adapter->transceiver = ecmd->transceiver; ++ adapter->autoneg = ecmd->autoneg; ++ } else { ++ ecmd->speed = adapter->link_speed; ++ ecmd->port = adapter->port_type; ++ ecmd->transceiver = adapter->transceiver; ++ ecmd->autoneg = adapter->autoneg; ++ } ++ + ecmd->duplex = DUPLEX_FULL; +- ecmd->autoneg = AUTONEG_DISABLE; ++ ecmd->phy_address = (adapter->hba_port_num << 4) | ++ (adapter->port_name[adapter->hba_port_num]); ++ switch (ecmd->port) { ++ case PORT_FIBRE: ++ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); ++ break; ++ case PORT_TP: ++ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP); ++ break; ++ } ++ ++ if (ecmd->autoneg) { ++ ecmd->supported |= SUPPORTED_1000baseT_Full; ++ ecmd->advertising |= (ADVERTISED_10000baseT_Full | ++ ADVERTISED_1000baseT_Full); ++ } ++ + return 0; + } + ++static int be_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_phy_info phy_info; ++ u16 mac_speed=0; ++ u16 dac_cable_len=0; ++ u16 port_speed = 0; ++ int status; ++ ++ status = be_cmd_get_phy_info(adapter, &phy_info); ++ if (status) { ++ dev_warn(&adapter->pdev->dev, "port speed set failed.\n"); ++ return status; ++ } ++ ++ if (ecmd->autoneg == AUTONEG_ENABLE) { ++ switch(phy_info.interface_type) { ++ case PHY_TYPE_SFP_1GB: ++ case PHY_TYPE_BASET_1GB: ++ case PHY_TYPE_BASEX_1GB: ++ case PHY_TYPE_SGMII: ++ mac_speed = SPEED_AUTONEG_1GB_100MB_10MB; ++ break; ++ case PHY_TYPE_SFP_PLUS_10GB: ++ dev_warn(&adapter->pdev->dev, ++ "Autoneg not supported on this module. \n"); ++ return -EINVAL; ++ case PHY_TYPE_KR_10GB: ++ case PHY_TYPE_KX4_10GB: ++ mac_speed = SPEED_AUTONEG_10GB_1GB; ++ break; ++ case PHY_TYPE_BASET_10GB: ++ mac_speed = SPEED_AUTONEG_10GB_1GB_100MB; ++ break; ++ } ++ } else if(ecmd->autoneg == AUTONEG_DISABLE) { ++ if(ecmd->speed == SPEED_10) { ++ mac_speed = SPEED_FORCED_10MB; ++ } else if(ecmd->speed == SPEED_100) { ++ mac_speed = SPEED_FORCED_100MB; ++ } else if(ecmd->speed == SPEED_1000) { ++ mac_speed = SPEED_FORCED_1GB; ++ } else if(ecmd->speed == SPEED_10000) { ++ mac_speed = SPEED_FORCED_10GB; ++ } ++ } ++ ++ status = be_cmd_get_port_speed(adapter, adapter->hba_port_num, ++ &dac_cable_len, &port_speed); ++ ++ if (!status && port_speed != mac_speed) ++ status = be_cmd_set_port_speed_v1(adapter, ++ adapter->hba_port_num, mac_speed, ++ dac_cable_len); ++ if (status) ++ dev_warn(&adapter->pdev->dev, "port speed set failed.\n"); ++ ++ return status; ++ ++} ++ + static void + be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) + { + struct be_adapter *adapter = netdev_priv(netdev); + +- ring->rx_max_pending = adapter->rx_obj.q.len; +- ring->tx_max_pending = adapter->tx_obj.q.len; ++ ring->rx_max_pending = adapter->rx_obj[0].q.len; ++ ring->tx_max_pending = adapter->tx_obj[0].q.len; + +- ring->rx_pending = atomic_read(&adapter->rx_obj.q.used); +- ring->tx_pending = atomic_read(&adapter->tx_obj.q.used); ++ ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used); ++ ring->tx_pending = atomic_read(&adapter->tx_obj[0].q.used); + } + + static void +@@ -312,7 +615,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) + struct be_adapter *adapter = netdev_priv(netdev); + + be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause); +- ecmd->autoneg = 0; ++ ecmd->autoneg = adapter->autoneg; + } + + static int +@@ -334,6 +637,203 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) + return status; + } + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) ++static int ++be_phys_id(struct net_device *netdev, u32 data) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ int status; ++ u32 cur; ++ ++ be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur); ++ ++ if (cur == BEACON_STATE_ENABLED) ++ return 0; ++ ++ if (data < 2) ++ data = 2; ++ ++ status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, ++ BEACON_STATE_ENABLED); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(data*HZ); ++ ++ status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, ++ BEACON_STATE_DISABLED); ++ ++ return status; ++} ++#else ++static int ++be_set_phys_id(struct net_device *netdev, ++ enum ethtool_phys_id_state state) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ switch (state) { ++ case ETHTOOL_ID_ACTIVE: ++ be_cmd_get_beacon_state(adapter, adapter->hba_port_num, ++ &adapter->beacon_state); ++ return 1; /* cycle on/off once per second */ ++ ++ case ETHTOOL_ID_ON: ++ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, ++ BEACON_STATE_ENABLED); ++ break; ++ ++ case ETHTOOL_ID_OFF: ++ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, ++ BEACON_STATE_DISABLED); ++ break; ++ ++ case ETHTOOL_ID_INACTIVE: ++ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, ++ adapter->beacon_state); ++ } ++ ++ return 0; ++} ++#endif ++ ++static bool ++be_is_wol_supported(struct be_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ ++ if (!be_physfn(adapter)) ++ return false; ++ ++ switch (pdev->subsystem_device) { ++ case OC_SUBSYS_DEVICE_ID1: ++ case OC_SUBSYS_DEVICE_ID2: ++ case OC_SUBSYS_DEVICE_ID3: ++ case OC_SUBSYS_DEVICE_ID4: ++ return false; ++ default: ++ return true; ++ } ++} ++ ++static void ++be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ if (be_is_wol_supported(adapter)) ++ wol->supported = WAKE_MAGIC; ++ if (adapter->wol) ++ wol->wolopts = WAKE_MAGIC; ++ else ++ wol->wolopts = 0; ++ memset(&wol->sopass, 0, sizeof(wol->sopass)); ++} ++ ++static int ++be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ if (wol->wolopts & ~WAKE_MAGIC) ++ return -EOPNOTSUPP; ++ ++ if (!be_is_wol_supported(adapter)) { ++ dev_warn(&adapter->pdev->dev, ++ "WOL not supported for this subsystemid: %x\n", ++ adapter->pdev->subsystem_device); ++ return -EOPNOTSUPP; ++ } ++ ++ if (wol->wolopts & WAKE_MAGIC) ++ adapter->wol = true; ++ else ++ adapter->wol = false; ++ ++ return 0; ++} ++ ++static int ++be_test_ddr_dma(struct be_adapter *adapter) ++{ ++ int ret, i; ++ struct be_dma_mem ddrdma_cmd; ++ u64 pattern[2] = {0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL}; ++ ++ ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); ++ ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, ++ &ddrdma_cmd.dma); ++ if (!ddrdma_cmd.va) { ++ dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < 2; i++) { ++ ret = be_cmd_ddr_dma_test(adapter, pattern[i], ++ 4096, &ddrdma_cmd); ++ if (ret != 0) ++ goto err; ++ } ++ ++err: ++ pci_free_consistent(adapter->pdev, ddrdma_cmd.size, ++ ddrdma_cmd.va, ddrdma_cmd.dma); ++ return ret; ++} ++ ++static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type, ++ u64 *status) ++{ ++ be_cmd_set_loopback(adapter, adapter->hba_port_num, ++ loopback_type, 1); ++ *status = be_cmd_loopback_test(adapter, adapter->hba_port_num, ++ loopback_type, 1500, ++ 2, 0xabc); ++ be_cmd_set_loopback(adapter, adapter->hba_port_num, ++ BE_NO_LOOPBACK, 1); ++ return *status; ++} ++ ++static void ++be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ int link_status; ++ u8 mac_speed = 0; ++ u16 qos_link_speed = 0; ++ ++ memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM); ++ ++ if (test->flags & ETH_TEST_FL_OFFLINE) { ++ if (be_loopback_test(adapter, BE_MAC_LOOPBACK, ++ &data[0]) != 0) { ++ test->flags |= ETH_TEST_FL_FAILED; ++ } ++ if (be_loopback_test(adapter, BE_PHY_LOOPBACK, ++ &data[1]) != 0) { ++ test->flags |= ETH_TEST_FL_FAILED; ++ } ++ if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, ++ &data[2]) != 0) { ++ test->flags |= ETH_TEST_FL_FAILED; ++ } ++ } ++ ++ if (be_test_ddr_dma(adapter) != 0) { ++ data[3] = 1; ++ test->flags |= ETH_TEST_FL_FAILED; ++ } ++ ++ if (be_cmd_link_status_query(adapter, &link_status, &mac_speed, ++ &qos_link_speed, 0) != 0) { ++ test->flags |= ETH_TEST_FL_FAILED; ++ data[4] = -1; ++ } else if (!mac_speed) { ++ test->flags |= ETH_TEST_FL_FAILED; ++ data[4] = 1; ++ } ++ ++} ++ ++#ifdef HAVE_ETHTOOL_FLASH + static int + be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) + { +@@ -347,11 +847,73 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) + + return be_load_fw(adapter, file_name); + } ++#endif + +-const struct ethtool_ops be_ethtool_ops = { ++static int ++be_get_eeprom_len(struct net_device *netdev) ++{ ++ return BE_READ_SEEPROM_LEN; ++} ++ ++static int ++be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, ++ uint8_t *data) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_dma_mem eeprom_cmd; ++ struct be_cmd_resp_seeprom_read *resp; ++ int status; ++ ++ if (!eeprom->len) ++ return -EINVAL; ++ ++ eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16); ++ ++ memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem)); ++ eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read); ++ eeprom_cmd.va = pci_alloc_consistent(adapter->pdev, eeprom_cmd.size, ++ &eeprom_cmd.dma); ++ ++ if (!eeprom_cmd.va) { ++ dev_err(&adapter->pdev->dev, ++ "Memory allocation failure. Could not read eeprom\n"); ++ return -ENOMEM; ++ } ++ ++ status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd); ++ ++ if (!status) { ++ resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va; ++ memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len); ++ } ++ pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va, ++ eeprom_cmd.dma); ++ ++ return status; ++} ++ ++static int be_set_tso(struct net_device *netdev, uint32_t data) ++{ ++ if (data) { ++ netdev->features |= NETIF_F_TSO; ++ netdev->features |= NETIF_F_TSO6; ++ } else { ++ netdev->features &= ~NETIF_F_TSO; ++ netdev->features &= ~NETIF_F_TSO6; ++ } ++ return 0; ++} ++ ++ ++struct ethtool_ops be_ethtool_ops = { + .get_settings = be_get_settings, ++ .set_settings = be_set_settings, + .get_drvinfo = be_get_drvinfo, ++ .get_wol = be_get_wol, ++ .set_wol = be_set_wol, + .get_link = ethtool_op_get_link, ++ .get_eeprom_len = be_get_eeprom_len, ++ .get_eeprom = be_read_eeprom, + .get_coalesce = be_get_coalesce, + .set_coalesce = be_set_coalesce, + .get_ringparam = be_get_ringparam, +@@ -364,9 +926,21 @@ const struct ethtool_ops be_ethtool_ops = { + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, +- .set_tso = ethtool_op_set_tso, ++ .set_tso = be_set_tso, + .get_strings = be_get_stat_strings, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) ++ .phys_id = be_phys_id, + .get_stats_count = be_get_stats_count, ++ .self_test_count = be_self_test_count, ++#else ++ .set_phys_id = be_set_phys_id, ++ .get_sset_count = be_get_sset_count, ++#endif + .get_ethtool_stats = be_get_ethtool_stats, ++ .get_regs_len = be_get_reg_len, ++ .get_regs = be_get_regs, ++#ifdef HAVE_ETHTOOL_FLASH + .flash_device = be_do_flash, ++#endif ++ .self_test = be_self_test + }; +diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h +index a3394b4..f871d8c 100644 +--- a/drivers/net/benet/be_hw.h ++++ b/drivers/net/benet/be_hw.h +@@ -1,18 +1,18 @@ + /* +- * Copyright (C) 2005 - 2009 ServerEngines ++ * Copyright (C) 2005 - 2011 Emulex + * 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 ++ * 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 ++ * linux-drivers@emulex.com + * +- * ServerEngines +- * 209 N. Fair Oaks Ave +- * Sunnyvale, CA 94085 ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 + */ + + /********* Mailbox door bell *************/ +@@ -26,24 +26,34 @@ + * queue entry. + */ + #define MPU_MAILBOX_DB_OFFSET 0x160 +-#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */ ++#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */ + #define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */ + +-#define MPU_EP_CONTROL 0 ++#define MPU_EP_CONTROL 0 + + /********** MPU semphore ******************/ +-#define MPU_EP_SEMAPHORE_OFFSET 0xac ++#define MPU_EP_SEMAPHORE_OFFSET 0xac ++#define MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET 0x400 + #define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF + #define EP_SEMAPHORE_POST_ERR_MASK 0x1 + #define EP_SEMAPHORE_POST_ERR_SHIFT 31 + /* MPU semphore POST stage values */ +-#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */ +-#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */ ++#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */ ++#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */ + #define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */ + #define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */ + ++/* Lancer SLIPORT_CONTROL SLIPORT_STATUS registers */ ++#define SLIPORT_STATUS_OFFSET 0x404 ++#define SLIPORT_CONTROL_OFFSET 0x408 ++ ++#define SLIPORT_STATUS_ERR_MASK 0x80000000 ++#define SLIPORT_STATUS_RN_MASK 0x01000000 ++#define SLIPORT_STATUS_RDY_MASK 0x00800000 ++#define SLI_PORT_CONTROL_IP_MASK 0x08000000 ++ + /********* Memory BAR register ************/ +-#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc ++#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc + /* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt + * Disable" may still globally block interrupts in addition to individual + * interrupt masks; a mechanism for the device driver to block all interrupts +@@ -52,13 +62,70 @@ + */ + #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ + ++/********* Link Status CSR ****************/ ++#define PCICFG_PCIE_LINK_STATUS_OFFSET 0xd0 ++#define PCIE_LINK_STATUS_SPEED_MASK 0xFF /* bits 16 - 19 */ ++#define PCIE_LINK_STATUS_SPEED_SHIFT 16 ++#define PCIE_LINK_STATUS_NEG_WIDTH_MASK 0x3F /* bits 20 - 25 */ ++#define PCIE_LINK_STATUS_NEG_WIDTH_SHIFT 20 ++ ++/********* Link Capability CSR ************/ ++#define PCICFG_PCIE_LINK_CAP_OFFSET 0xcc ++#define PCIE_LINK_CAP_MAX_SPEED_MASK 0xFF /* bits 0 - 3 */ ++#define PCIE_LINK_CAP_MAX_SPEED_SHIFT 0 ++#define PCIE_LINK_CAP_MAX_WIDTH_MASK 0x3F /* bits 4 - 9 */ ++#define PCIE_LINK_CAP_MAX_WIDTH_SHIFT 4 ++ ++/********* PCI Function Capability ************/ ++#define BE_FUNCTION_CAPS_UNCLASSIFIED_STATS 0x1 ++#define BE_FUNCTION_CAPS_RSS 0x2 ++#define BE_FUNCTION_CAPS_PROMISCUOUS 0x4 ++#define BE_FUNCTION_CAPS_LEGACY_MODE 0x8 ++ ++/********* Power managment (WOL) **********/ ++#define PCICFG_PM_CONTROL_OFFSET 0x44 ++#define PCICFG_PM_CONTROL_MASK 0x108 /* bits 3 & 8 */ ++ ++/********* Online Control Registers *******/ ++#define PCICFG_ONLINE0 0xB0 ++#define PCICFG_ONLINE1 0xB4 ++ ++/********* UE Status and Mask Registers ***/ ++#define PCICFG_UE_STATUS_LOW 0xA0 ++#define PCICFG_UE_STATUS_HIGH 0xA4 ++#define PCICFG_UE_STATUS_LOW_MASK 0xA8 ++#define PCICFG_UE_STATUS_HI_MASK 0xAC ++ ++/******** SLI_INTF ***********************/ ++#define SLI_INTF_REG_OFFSET 0x58 ++#define SLI_INTF_VALID_MASK 0xE0000000 ++#define SLI_INTF_VALID 0xC0000000 ++#define SLI_INTF_HINT2_MASK 0x1F000000 ++#define SLI_INTF_HINT2_SHIFT 24 ++#define SLI_INTF_HINT1_MASK 0x00FF0000 ++#define SLI_INTF_HINT1_SHIFT 16 ++#define SLI_INTF_FAMILY_MASK 0x00000F00 ++#define SLI_INTF_FAMILY_SHIFT 8 ++#define SLI_INTF_IF_TYPE_MASK 0x0000F000 ++#define SLI_INTF_IF_TYPE_SHIFT 12 ++#define SLI_INTF_REV_MASK 0x000000F0 ++#define SLI_INTF_REV_SHIFT 4 ++#define SLI_INTF_FT_MASK 0x00000001 ++ ++/* SLI family */ ++#define BE_SLI_FAMILY 0x0 ++#define LANCER_A0_SLI_FAMILY 0xA ++ + /********* ISR0 Register offset **********/ +-#define CEV_ISR0_OFFSET 0xC18 ++#define CEV_ISR0_OFFSET 0xC18 + #define CEV_ISR_SIZE 4 + + /********* Event Q door bell *************/ + #define DB_EQ_OFFSET DB_CQ_OFFSET + #define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */ ++#define DB_EQ_RING_ID_EXT_MASK 0x3e00 /* bits 9-13 */ ++#define DB_EQ_RING_ID_EXT_MASK_SHIFT (2) /* qid bits 9-13 placing at 11-15 */ ++ + /* Clear the interrupt for this eq */ + #define DB_EQ_CLR_SHIFT (9) /* bit 9 */ + /* Must be 1 */ +@@ -69,12 +136,16 @@ + #define DB_EQ_REARM_SHIFT (29) /* bit 29 */ + + /********* Compl Q door bell *************/ +-#define DB_CQ_OFFSET 0x120 ++#define DB_CQ_OFFSET 0x120 + #define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ ++#define DB_CQ_RING_ID_EXT_MASK 0x7C00 /* bits 10-14 */ ++#define DB_CQ_RING_ID_EXT_MASK_SHIFT (1) /* qid bits 10-14 ++ placing at 11-15 */ ++ + /* Number of event entries processed */ +-#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ ++#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ + /* Rearm bit */ +-#define DB_CQ_REARM_SHIFT (29) /* bit 29 */ ++#define DB_CQ_REARM_SHIFT (29) /* bit 29 */ + + /********** TX ULP door bell *************/ + #define DB_TXULP1_OFFSET 0x60 +@@ -84,25 +155,103 @@ + #define DB_TXULP_NUM_POSTED_MASK 0x3FFF /* bits 16 - 29 */ + + /********** RQ(erx) door bell ************/ +-#define DB_RQ_OFFSET 0x100 ++#define DB_RQ_OFFSET 0x100 + #define DB_RQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ + /* Number of rx frags posted */ + #define DB_RQ_NUM_POSTED_SHIFT (24) /* bits 24 - 31 */ + + /********** MCC door bell ************/ +-#define DB_MCCQ_OFFSET 0x140 ++#define DB_MCCQ_OFFSET 0x140 + #define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */ + /* Number of entries posted */ + #define DB_MCCQ_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */ + ++/********** SRIOV VF PCICFG OFFSET ********/ ++#define SRIOV_VF_PCICFG_OFFSET (4096) ++ ++/********** FAT TABLE ********/ ++#define RETRIEVE_FAT 0 ++#define QUERY_FAT 1 ++ ++/* Flashrom related descriptors */ ++#define IMAGE_TYPE_FIRMWARE 160 ++#define IMAGE_TYPE_BOOTCODE 224 ++#define IMAGE_TYPE_OPTIONROM 32 ++ ++#define NUM_FLASHDIR_ENTRIES 32 ++ ++#define IMG_TYPE_ISCSI_ACTIVE 0 ++#define IMG_TYPE_REDBOOT 1 ++#define IMG_TYPE_BIOS 2 ++#define IMG_TYPE_PXE_BIOS 3 ++#define IMG_TYPE_FCOE_BIOS 8 ++#define IMG_TYPE_ISCSI_BACKUP 9 ++#define IMG_TYPE_FCOE_FW_ACTIVE 10 ++#define IMG_TYPE_FCOE_FW_BACKUP 11 ++#define IMG_TYPE_NCSI_FW 13 ++#define IMG_TYPE_PHY_FW 99 ++#define TN_8022 13 ++ ++#define ILLEGAL_IOCTL_REQ 2 ++#define FLASHROM_OPER_PHY_FLASH 9 ++#define FLASHROM_OPER_PHY_SAVE 10 ++#define FLASHROM_OPER_FLASH 1 ++#define FLASHROM_OPER_SAVE 2 ++#define FLASHROM_OPER_REPORT 4 ++ ++#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */ ++#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */ ++#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */ ++#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */ ++#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */ ++#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */ ++#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144) ++#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 (262144) ++ ++#define FLASH_NCSI_MAGIC (0x16032009) ++#define FLASH_NCSI_DISABLED (0) ++#define FLASH_NCSI_ENABLED (1) ++ ++#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000) ++ ++/* Offsets for components on Flash. */ ++#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576) ++#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296) ++#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016) ++#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736) ++#define FLASH_iSCSI_BIOS_START_g2 (7340032) ++#define FLASH_PXE_BIOS_START_g2 (7864320) ++#define FLASH_FCoE_BIOS_START_g2 (524288) ++#define FLASH_REDBOOT_START_g2 (0) ++ ++#define FLASH_NCSI_START_g3 (15990784) ++#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152) ++#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304) ++#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456) ++#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608) ++#define FLASH_iSCSI_BIOS_START_g3 (12582912) ++#define FLASH_PXE_BIOS_START_g3 (13107200) ++#define FLASH_FCoE_BIOS_START_g3 (13631488) ++#define FLASH_REDBOOT_START_g3 (262144) ++#define FLASH_PHY_FW_START_g3 (1310720) ++ ++/************* Rx Packet Type Encoding **************/ ++#define BE_UNICAST_PACKET 0 ++#define BE_MULTICAST_PACKET 1 ++#define BE_BROADCAST_PACKET 2 ++#define BE_RSVD_PACKET 3 ++ + /* + * BE descriptors: host memory data structures whose formats + * are hardwired in BE silicon. + */ + /* Event Queue Descriptor */ +-#define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */ +-#define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */ +-#define EQ_ENTRY_RES_ID_SHIFT 16 ++#define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */ ++#define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */ ++#define EQ_ENTRY_RES_ID_SHIFT 16 ++ ++#define BE_MAC_PROMISCUOUS 62 /* Promiscuous mode */ ++ + struct be_eq_entry { + u32 evt; + }; +@@ -126,7 +275,7 @@ struct amap_eth_hdr_wrb { + u8 event; + u8 crc; + u8 forward; +- u8 ipsec; ++ u8 lso6; + u8 mgmt; + u8 ipcs; + u8 udpcs; +@@ -151,7 +300,7 @@ struct be_eth_hdr_wrb { + * offset/shift/mask of each field */ + struct amap_eth_tx_compl { + u8 wrb_index[16]; /* dword 0 */ +- u8 ct[2]; /* dword 0 */ ++ u8 ct[2]; /* dword 0 */ + u8 port[2]; /* dword 0 */ + u8 rsvd0[8]; /* dword 0 */ + u8 status[4]; /* dword 0 */ +@@ -179,10 +328,10 @@ struct be_eth_rx_d { + + /* RX Compl Queue Descriptor */ + +-/* Pseudo amap definition for eth_rx_compl in which each bit of the +- * actual structure is defined as a byte: used to calculate ++/* Pseudo amap definition for BE2 and BE3 legacy mode eth_rx_compl in which ++ * each bit of the actual structure is defined as a byte: used to calculate + * offset/shift/mask of each field */ +-struct amap_eth_rx_compl { ++struct amap_eth_rx_compl_v0 { + u8 vlan_tag[16]; /* dword 0 */ + u8 pktsize[14]; /* dword 0 */ + u8 port; /* dword 0 */ +@@ -213,39 +362,91 @@ struct amap_eth_rx_compl { + u8 rsshash[32]; /* dword 3 */ + } __packed; + ++/* Pseudo amap definition for BE3 native mode eth_rx_compl in which ++ * each bit of the actual structure is defined as a byte: used to calculate ++ * offset/shift/mask of each field */ ++struct amap_eth_rx_compl_v1 { ++ u8 vlan_tag[16]; /* dword 0 */ ++ u8 pktsize[14]; /* dword 0 */ ++ u8 vtp; /* dword 0 */ ++ u8 ip_opt; /* 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 l4_cksm; /* dword 1 */ ++ u8 ip_version; /* dword 1 */ ++ u8 macdst[7]; /* dword 1 */ ++ u8 rsvd0; /* dword 1 */ ++ u8 fragndx[10]; /* dword 1 */ ++ u8 ct[2]; /* dword 1 */ ++ u8 sw; /* dword 1 */ ++ u8 numfrags[3]; /* dword 1 */ ++ u8 rss_flush; /* dword 2 */ ++ u8 cast_enc[2]; /* dword 2 */ ++ u8 vtm; /* dword 2 */ ++ u8 rss_bank; /* dword 2 */ ++ u8 port[2]; /* dword 2 */ ++ u8 vntagp; /* dword 2 */ ++ u8 header_len[8]; /* dword 2 */ ++ u8 header_split[2]; /* dword 2 */ ++ u8 rsvd1[13]; /* dword 2 */ ++ u8 valid; /* dword 2 */ ++ u8 rsshash[32]; /* dword 3 */ ++} __packed; ++ + struct be_eth_rx_compl { + u32 dw[4]; + }; + +-/* Flashrom related descriptors */ +-#define IMAGE_TYPE_FIRMWARE 160 +-#define IMAGE_TYPE_BOOTCODE 224 +-#define IMAGE_TYPE_OPTIONROM 32 ++struct mgmt_hba_attribs { ++ u8 flashrom_version_string[32]; ++ u8 manufacturer_name[32]; ++ u32 supported_modes; ++ u32 rsvd0[3]; ++ u8 ncsi_ver_string[12]; ++ u32 default_extended_timeout; ++ u8 controller_model_number[32]; ++ u8 controller_description[64]; ++ u8 controller_serial_number[32]; ++ u8 ip_version_string[32]; ++ u8 firmware_version_string[32]; ++ u8 bios_version_string[32]; ++ u8 redboot_version_string[32]; ++ u8 driver_version_string[32]; ++ u8 fw_on_flash_version_string[32]; ++ u32 functionalities_supported; ++ u16 max_cdblength; ++ u8 asic_revision; ++ u8 generational_guid[16]; ++ u8 hba_port_count; ++ u16 default_link_down_timeout; ++ u8 iscsi_ver_min_max; ++ u8 multifunction_device; ++ u8 cache_valid; ++ u8 hba_status; ++ u8 max_domains_supported; ++ u8 phy_port; ++ u32 firmware_post_status; ++ u32 hba_mtu[8]; ++ u32 rsvd1[4]; ++}; + +-#define NUM_FLASHDIR_ENTRIES 32 +- +-#define FLASHROM_TYPE_ISCSI_ACTIVE 0 +-#define FLASHROM_TYPE_BIOS 2 +-#define FLASHROM_TYPE_PXE_BIOS 3 +-#define FLASHROM_TYPE_FCOE_BIOS 8 +-#define FLASHROM_TYPE_ISCSI_BACKUP 9 +-#define FLASHROM_TYPE_FCOE_FW_ACTIVE 10 +-#define FLASHROM_TYPE_FCOE_FW_BACKUP 11 +- +-#define FLASHROM_OPER_FLASH 1 +-#define FLASHROM_OPER_SAVE 2 +- +-#define FLASH_IMAGE_MAX_SIZE (1310720) /* Max firmware image size */ +-#define FLASH_BIOS_IMAGE_MAX_SIZE (262144) /* Max OPTION ROM image sz */ +- +-/* Offsets for components on Flash. */ +-#define FLASH_iSCSI_PRIMARY_IMAGE_START (1048576) +-#define FLASH_iSCSI_BACKUP_IMAGE_START (2359296) +-#define FLASH_FCoE_PRIMARY_IMAGE_START (3670016) +-#define FLASH_FCoE_BACKUP_IMAGE_START (4980736) +-#define FLASH_iSCSI_BIOS_START (7340032) +-#define FLASH_PXE_BIOS_START (7864320) +-#define FLASH_FCoE_BIOS_START (524288) ++struct mgmt_controller_attrib { ++ struct mgmt_hba_attribs hba_attribs; ++ u16 pci_vendor_id; ++ u16 pci_device_id; ++ u16 pci_sub_vendor_id; ++ u16 pci_sub_system_id; ++ u8 pci_bus_number; ++ u8 pci_device_number; ++ u8 pci_function_number; ++ u8 interface_type; ++ u64 unique_identifier; ++ u32 rsvd0[5]; ++}; + + struct controller_id { + u32 vendor; +@@ -254,7 +455,20 @@ struct controller_id { + u32 subdevice; + }; + +-struct flash_file_hdr { ++struct flash_comp { ++ unsigned long offset; ++ int optype; ++ int size; ++}; ++ ++struct image_hdr { ++ u32 imageid; ++ u32 imageoffset; ++ u32 imagelength; ++ u32 image_checksum; ++ u8 image_version[32]; ++}; ++struct flash_file_hdr_g2 { + u8 sign[32]; + u32 cksum; + u32 antidote; +@@ -266,6 +480,17 @@ struct flash_file_hdr { + u8 build[24]; + }; + ++struct flash_file_hdr_g3 { ++ u8 sign[52]; ++ u8 ufi_version[4]; ++ u32 file_len; ++ u32 cksum; ++ u32 antidote; ++ u32 num_imgs; ++ u8 build[24]; ++ u8 rsvd[32]; ++}; ++ + struct flash_section_hdr { + u32 format_rev; + u32 cksum; +@@ -299,3 +524,19 @@ struct flash_section_info { + struct flash_section_hdr fsec_hdr; + struct flash_section_entry fsec_entry[32]; + }; ++ ++struct flash_ncsi_image_hdr { ++ u32 magic; ++ u8 hdr_len; ++ u8 type; ++ u16 hdr_ver; ++ u8 rsvd0[2]; ++ u16 load_offset; ++ u32 len; ++ u32 flash_offset; ++ u8 ver[16]; ++ u8 name[24]; ++ u32 img_cksum; ++ u8 rsvd1[4]; ++ u32 hdr_cksum; ++}; +diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c +index 000e377..f501aa3 100644 +--- a/drivers/net/benet/be_main.c ++++ b/drivers/net/benet/be_main.c +@@ -1,18 +1,18 @@ + /* +- * Copyright (C) 2005 - 2009 ServerEngines ++ * Copyright (C) 2005 - 2011 Emulex + * 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 ++ * 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 ++ * linux-drivers@emulex.com + * +- * ServerEngines +- * 209 N. Fair Oaks Ave +- * Sunnyvale, CA 94085 ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 + */ + + #include "be.h" +@@ -22,23 +22,119 @@ + MODULE_VERSION(DRV_VER); + MODULE_DEVICE_TABLE(pci, be_dev_ids); + MODULE_DESCRIPTION(DRV_DESC " " DRV_VER); +-MODULE_AUTHOR("ServerEngines Corporation"); ++MODULE_AUTHOR("Emulex Corporation"); + MODULE_LICENSE("GPL"); ++MODULE_INFO(supported, "external"); + +-static unsigned int rx_frag_size = 2048; +-module_param(rx_frag_size, uint, S_IRUGO); +-MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); ++static ushort rx_frag_size = 2048; ++static unsigned int num_vfs; ++static unsigned int msix = 1; ++module_param(rx_frag_size, ushort, S_IRUGO); ++module_param(num_vfs, uint, S_IRUGO); ++module_param(msix, uint, S_IRUGO); ++MODULE_PARM_DESC(rx_frag_size, "Size of receive fragment buffer" ++ " - 2048 (default), 4096 or 8192"); ++MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize"); ++MODULE_PARM_DESC(msix, "Enable and disable the MSI" ++ "x (By default MSIx is enabled)"); ++static unsigned int gro = 1; ++module_param(gro, uint, S_IRUGO); ++MODULE_PARM_DESC(gro, "Enable or Disable GRO. Enabled by default"); ++ ++static unsigned int multi_rxq = true; ++module_param(multi_rxq, uint, S_IRUGO); ++MODULE_PARM_DESC(multi_rxq, "Multi Rx Queue support. Enabled by default"); + + static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { + { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, + { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, + { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, + { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, +- { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, ++ /* ++ * Lancer is not part of Palau 4.0 ++ * { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)}, ++ */ + { 0 } + }; + MODULE_DEVICE_TABLE(pci, be_dev_ids); + ++/* UE Status Low CSR */ ++static char *ue_status_low_desc[] = { ++ "CEV", ++ "CTX", ++ "DBUF", ++ "ERX", ++ "Host", ++ "MPU", ++ "NDMA", ++ "PTC ", ++ "RDMA ", ++ "RXF ", ++ "RXIPS ", ++ "RXULP0 ", ++ "RXULP1 ", ++ "RXULP2 ", ++ "TIM ", ++ "TPOST ", ++ "TPRE ", ++ "TXIPS ", ++ "TXULP0 ", ++ "TXULP1 ", ++ "UC ", ++ "WDMA ", ++ "TXULP2 ", ++ "HOST1 ", ++ "P0_OB_LINK ", ++ "P1_OB_LINK ", ++ "HOST_GPIO ", ++ "MBOX ", ++ "AXGMAC0", ++ "AXGMAC1", ++ "JTAG", ++ "MPU_INTPEND" ++}; ++ ++/* UE Status High CSR */ ++static char *ue_status_hi_desc[] = { ++ "LPCMEMHOST", ++ "MGMT_MAC", ++ "PCS0ONLINE", ++ "MPU_IRAM", ++ "PCS1ONLINE", ++ "PCTL0", ++ "PCTL1", ++ "PMEM", ++ "RR", ++ "TXPB", ++ "RXPP", ++ "XAUI", ++ "TXP", ++ "ARM", ++ "IPC", ++ "HOST2", ++ "HOST3", ++ "HOST4", ++ "HOST5", ++ "HOST6", ++ "HOST7", ++ "HOST8", ++ "HOST9", ++ "NETC", ++ "Unknown", ++ "Unknown", ++ "Unknown", ++ "Unknown", ++ "Unknown", ++ "Unknown", ++ "Unknown", ++ "Unknown" ++}; ++ ++static inline bool be_multi_rxq(struct be_adapter *adapter) ++{ ++ return (adapter->num_rx_qs > 1); ++} ++ + static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) + { + struct be_dma_mem *mem = &q->dma_mem; +@@ -69,6 +165,9 @@ static void be_intr_set(struct be_adapter *adapter, bool enable) + u32 reg = ioread32(addr); + u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; + ++ if (adapter->eeh_err) ++ return; ++ + if (!enabled && enable) + reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; + else if (enabled && !enable) +@@ -84,6 +183,8 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted) + u32 val = 0; + val |= qid & DB_RQ_RING_ID_MASK; + val |= posted << DB_RQ_NUM_POSTED_SHIFT; ++ ++ wmb(); + iowrite32(val, adapter->db + DB_RQ_OFFSET); + } + +@@ -92,6 +193,8 @@ static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted) + u32 val = 0; + val |= qid & DB_TXULP_RING_ID_MASK; + val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; ++ ++ wmb(); + iowrite32(val, adapter->db + DB_TXULP1_OFFSET); + } + +@@ -100,6 +203,12 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid, + { + u32 val = 0; + val |= qid & DB_EQ_RING_ID_MASK; ++ val |= ((qid & DB_EQ_RING_ID_EXT_MASK) << ++ DB_EQ_RING_ID_EXT_MASK_SHIFT); ++ ++ if (adapter->eeh_err) ++ return; ++ + if (arm) + val |= 1 << DB_EQ_REARM_SHIFT; + if (clear_int) +@@ -113,6 +222,12 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) + { + u32 val = 0; + val |= qid & DB_CQ_RING_ID_MASK; ++ val |= ((qid & DB_CQ_RING_ID_EXT_MASK) << ++ DB_CQ_RING_ID_EXT_MASK_SHIFT); ++ ++ if (adapter->eeh_err) ++ return; ++ + if (arm) + val |= 1 << DB_CQ_REARM_SHIFT; + val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; +@@ -124,96 +239,250 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) + struct be_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + int status = 0; ++ u8 current_mac[ETH_ALEN]; ++ u32 pmac_id = adapter->pmac_id; + +- status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ status = be_cmd_mac_addr_query(adapter, current_mac, ++ MAC_ADDRESS_TYPE_NETWORK, false, ++ adapter->if_handle); + if (status) +- return status; ++ goto err; ++ ++ if (!memcmp(addr->sa_data, current_mac, ETH_ALEN)) ++ goto done; + + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, +- adapter->if_handle, &adapter->pmac_id); +- if (!status) ++ adapter->if_handle, &adapter->pmac_id, 0); ++ ++ if (!status) { ++ status = be_cmd_pmac_del(adapter, adapter->if_handle, ++ pmac_id, 0); + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ goto done; ++ } + +- return status; ++err: ++ if (status == MCC_STATUS_UNAUTHORIZED_REQUEST) ++ return -EPERM; ++ else ++ dev_err(&adapter->pdev->dev, "MAC %pM set Failed\n", ++ addr->sa_data); ++done: ++ return status; ++} ++ ++static void populate_be2_stats(struct be_adapter *adapter) ++{ ++ ++ struct be_drv_stats *drvs = &adapter->drv_stats; ++ struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); ++ struct be_port_rxf_stats_v0 *port_stats = ++ be_port_rxf_stats_from_cmd(adapter); ++ struct be_rxf_stats_v0 *rxf_stats = ++ be_rxf_stats_from_cmd(adapter); ++ ++ drvs->rx_pause_frames = port_stats->rx_pause_frames; ++ drvs->rx_crc_errors = port_stats->rx_crc_errors; ++ drvs->rx_control_frames = port_stats->rx_control_frames; ++ drvs->rx_in_range_errors = port_stats->rx_in_range_errors; ++ drvs->rx_frame_too_long = port_stats->rx_frame_too_long; ++ drvs->rx_dropped_runt = port_stats->rx_dropped_runt; ++ drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; ++ drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; ++ drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; ++ drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow; ++ drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; ++ drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; ++ drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; ++ drvs->rx_out_range_errors = port_stats->rx_out_range_errors; ++ drvs->rx_input_fifo_overflow_drop = ++ port_stats->rx_input_fifo_overflow; ++ drvs->rx_dropped_header_too_small = ++ port_stats->rx_dropped_header_too_small; ++ drvs->rx_address_match_errors = ++ port_stats->rx_address_match_errors; ++ drvs->rx_alignment_symbol_errors = ++ port_stats->rx_alignment_symbol_errors; ++ ++ drvs->tx_pauseframes = port_stats->tx_pauseframes; ++ drvs->tx_controlframes = port_stats->tx_controlframes; ++ ++ if (adapter->port_num) ++ drvs->jabber_events = ++ rxf_stats->port1_jabber_events; ++ else ++ drvs->jabber_events = ++ rxf_stats->port0_jabber_events; ++ drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; ++ drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; ++ drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; ++ drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; ++ drvs->forwarded_packets = rxf_stats->forwarded_packets; ++ drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; ++ drvs->rx_drops_no_tpre_descr = ++ rxf_stats->rx_drops_no_tpre_descr; ++ drvs->rx_drops_too_many_frags = ++ rxf_stats->rx_drops_too_many_frags; ++ adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; ++} ++ ++static void populate_be3_stats(struct be_adapter *adapter) ++{ ++ struct be_drv_stats *drvs = &adapter->drv_stats; ++ struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); ++ ++ struct be_rxf_stats_v1 *rxf_stats = ++ be_rxf_stats_from_cmd(adapter); ++ struct be_port_rxf_stats_v1 *port_stats = ++ be_port_rxf_stats_from_cmd(adapter); ++ ++ drvs->pmem_fifo_overflow_drop = port_stats->pmem_fifo_overflow_drop; ++ drvs->rx_priority_pause_frames = port_stats->rx_priority_pause_frames; ++ drvs->rx_pause_frames = port_stats->rx_pause_frames; ++ drvs->rx_crc_errors = port_stats->rx_crc_errors; ++ drvs->rx_control_frames = port_stats->rx_control_frames; ++ drvs->rx_in_range_errors = port_stats->rx_in_range_errors; ++ drvs->rx_frame_too_long = port_stats->rx_frame_too_long; ++ drvs->rx_dropped_runt = port_stats->rx_dropped_runt; ++ drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; ++ drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; ++ drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; ++ drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; ++ drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; ++ drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; ++ drvs->rx_out_range_errors = port_stats->rx_out_range_errors; ++ drvs->rx_dropped_header_too_small = ++ port_stats->rx_dropped_header_too_small; ++ drvs->rx_input_fifo_overflow_drop = ++ port_stats->rx_input_fifo_overflow_drop; ++ drvs->rx_address_match_errors = ++ port_stats->rx_address_match_errors; ++ drvs->rx_alignment_symbol_errors = ++ port_stats->rx_alignment_symbol_errors; ++ drvs->rxpp_fifo_overflow_drop = ++ port_stats->rxpp_fifo_overflow_drop; ++ drvs->tx_pauseframes = port_stats->tx_pauseframes; ++ drvs->tx_controlframes = port_stats->tx_controlframes; ++ drvs->jabber_events = port_stats->jabber_events; ++ drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; ++ drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; ++ drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; ++ drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; ++ drvs->forwarded_packets = rxf_stats->forwarded_packets; ++ drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; ++ drvs->rx_drops_no_tpre_descr = ++ rxf_stats->rx_drops_no_tpre_descr; ++ drvs->rx_drops_too_many_frags = ++ rxf_stats->rx_drops_too_many_frags; ++ adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; ++} ++ ++ ++static void accumulate_16bit_val(u32 *acc, u16 val) ++{ ++#define lo(x) (x & 0xFFFF) ++#define hi(x) (x & 0xFFFF0000) ++ bool wrapped = val < lo(*acc); ++ u32 newacc = hi(*acc) + val; ++ ++ if (wrapped) ++ newacc += 65536; ++ ACCESS_ONCE_RW(*acc) = newacc; ++} ++ ++void be_parse_stats(struct be_adapter *adapter) ++{ ++ struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter); ++ struct be_rx_obj *rxo; ++ int i; ++ ++ if (adapter->generation == BE_GEN3) { ++ populate_be3_stats(adapter); ++ } else { ++ populate_be2_stats(adapter); ++ } ++ ++ /* as erx_v1 is longer than v0, ok to use v1 defn for v0 access */ ++ for_all_rx_queues(adapter, rxo, i) { ++ /* below erx HW counter can actually wrap around after ++ * 65535. Driver accumulates a 32-bit value ++ */ ++ accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags, ++ (u16)erx->rx_drops_no_fragments[rxo->q.id]); ++ } + } + + void netdev_stats_update(struct be_adapter *adapter) + { +- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va); +- struct be_rxf_stats *rxf_stats = &hw_stats->rxf; +- struct be_port_rxf_stats *port_stats = +- &rxf_stats->port[adapter->port_num]; +- struct net_device_stats *dev_stats = &adapter->stats.net_stats; +- struct be_erx_stats *erx_stats = &hw_stats->erx; ++ struct be_drv_stats *drvs = &adapter->drv_stats; ++ struct net_device_stats *dev_stats = &adapter->net_stats; ++ struct be_rx_obj *rxo; ++ struct be_tx_obj *txo; ++ unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0; ++ int i; + +- dev_stats->rx_packets = drvr_stats(adapter)->be_rx_pkts; +- dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts; +- dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes; +- dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes; ++ for_all_rx_queues(adapter, rxo, i) { ++ pkts += rx_stats(rxo)->rx_pkts; ++ bytes += rx_stats(rxo)->rx_bytes; ++ mcast += rx_stats(rxo)->rx_mcast_pkts; ++ drops += rx_stats(rxo)->rx_drops_no_frags; ++ } ++ dev_stats->rx_packets = pkts; ++ dev_stats->rx_bytes = bytes; ++ dev_stats->multicast = mcast; ++ dev_stats->rx_dropped = drops; ++ ++ pkts = bytes = 0; ++ for_all_tx_queues(adapter, txo, i) { ++ pkts += tx_stats(txo)->be_tx_pkts; ++ bytes += tx_stats(txo)->be_tx_bytes; ++ } ++ dev_stats->tx_packets = pkts; ++ dev_stats->tx_bytes = bytes; + + /* bad pkts received */ +- dev_stats->rx_errors = port_stats->rx_crc_errors + +- port_stats->rx_alignment_symbol_errors + +- port_stats->rx_in_range_errors + +- port_stats->rx_out_range_errors + +- port_stats->rx_frame_too_long + +- port_stats->rx_dropped_too_small + +- port_stats->rx_dropped_too_short + +- port_stats->rx_dropped_header_too_small + +- port_stats->rx_dropped_tcp_length + +- port_stats->rx_dropped_runt + +- port_stats->rx_tcp_checksum_errs + +- port_stats->rx_ip_checksum_errs + +- port_stats->rx_udp_checksum_errs; +- +- /* no space in linux buffers: best possible approximation */ +- dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0]; ++ dev_stats->rx_errors = drvs->rx_crc_errors + ++ drvs->rx_alignment_symbol_errors + ++ drvs->rx_in_range_errors + ++ drvs->rx_out_range_errors + ++ drvs->rx_frame_too_long + ++ drvs->rx_dropped_too_small + ++ drvs->rx_dropped_too_short + ++ drvs->rx_dropped_header_too_small + ++ drvs->rx_dropped_tcp_length + ++ drvs->rx_dropped_runt + ++ drvs->rx_tcp_checksum_errs + ++ drvs->rx_ip_checksum_errs + ++ drvs->rx_udp_checksum_errs; + + /* detailed rx errors */ +- dev_stats->rx_length_errors = port_stats->rx_in_range_errors + +- port_stats->rx_out_range_errors + +- port_stats->rx_frame_too_long; ++ dev_stats->rx_length_errors = drvs->rx_in_range_errors + ++ drvs->rx_out_range_errors + ++ drvs->rx_frame_too_long; + +- /* receive ring buffer overflow */ +- dev_stats->rx_over_errors = 0; +- +- dev_stats->rx_crc_errors = port_stats->rx_crc_errors; ++ dev_stats->rx_crc_errors = drvs->rx_crc_errors; + + /* frame alignment errors */ +- dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; ++ dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors; + + /* receiver fifo overrun */ + /* drops_no_pbuf is no per i/f, it's per BE card */ +- dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + +- port_stats->rx_input_fifo_overflow + +- rxf_stats->rx_drops_no_pbuf; +- /* receiver missed packetd */ +- dev_stats->rx_missed_errors = 0; +- +- /* packet transmit problems */ +- dev_stats->tx_errors = 0; +- +- /* no space available in linux */ +- dev_stats->tx_dropped = 0; +- +- dev_stats->multicast = port_stats->rx_multicast_frames; +- dev_stats->collisions = 0; +- +- /* detailed tx_errors */ +- dev_stats->tx_aborted_errors = 0; +- dev_stats->tx_carrier_errors = 0; +- dev_stats->tx_fifo_errors = 0; +- dev_stats->tx_heartbeat_errors = 0; +- dev_stats->tx_window_errors = 0; ++ dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop + ++ drvs->rx_input_fifo_overflow_drop + ++ drvs->rx_drops_no_pbuf; + } + +-void be_link_status_update(struct be_adapter *adapter, bool link_up) ++void be_link_status_update(struct be_adapter *adapter, int link_status) + { + struct net_device *netdev = adapter->netdev; + + /* If link came up or went down */ +- if (adapter->link_up != link_up) { +- if (link_up) { ++ if (adapter->link_status != link_status) { ++ adapter->link_speed = -1; ++ if (link_status == LINK_UP) { + netif_start_queue(netdev); + netif_carrier_on(netdev); + printk(KERN_INFO "%s: Link up\n", netdev->name); +@@ -222,15 +491,15 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up) + netif_carrier_off(netdev); + printk(KERN_INFO "%s: Link down\n", netdev->name); + } +- adapter->link_up = link_up; ++ adapter->link_status = link_status; + } + } + + /* Update the EQ delay n BE based on the RX frags consumed / sec */ +-static void be_rx_eqd_update(struct be_adapter *adapter) ++static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo) + { +- struct be_eq_obj *rx_eq = &adapter->rx_eq; +- struct be_drvr_stats *stats = &adapter->stats.drvr_stats; ++ struct be_eq_obj *rx_eq = &rxo->rx_eq; ++ struct be_rx_stats *stats = &rxo->stats; + ulong now = jiffies; + u32 eqd; + +@@ -247,19 +516,17 @@ static void be_rx_eqd_update(struct be_adapter *adapter) + if ((now - stats->rx_fps_jiffies) < HZ) + return; + +- stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) / ++ stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) / + ((now - stats->rx_fps_jiffies) / HZ); + + stats->rx_fps_jiffies = now; +- stats->be_prev_rx_frags = stats->be_rx_frags; +- eqd = stats->be_rx_fps / 110000; ++ stats->prev_rx_frags = stats->rx_frags; ++ eqd = stats->rx_fps / 110000; + eqd = eqd << 3; + if (eqd > rx_eq->max_eqd) + eqd = rx_eq->max_eqd; + if (eqd < rx_eq->min_eqd) + eqd = rx_eq->min_eqd; +- if (eqd < 10) +- eqd = 0; + if (eqd != rx_eq->cur_eqd) + be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd); + +@@ -270,7 +537,7 @@ static struct net_device_stats *be_get_stats(struct net_device *dev) + { + struct be_adapter *adapter = netdev_priv(dev); + +- return &adapter->stats.net_stats; ++ return &adapter->net_stats; + } + + static u32 be_calc_rate(u64 bytes, unsigned long ticks) +@@ -284,9 +551,9 @@ static u32 be_calc_rate(u64 bytes, unsigned long ticks) + return rate; + } + +-static void be_tx_rate_update(struct be_adapter *adapter) ++static void be_tx_rate_update(struct be_tx_obj *txo) + { +- struct be_drvr_stats *stats = drvr_stats(adapter); ++ struct be_tx_stats *stats = tx_stats(txo); + ulong now = jiffies; + + /* Wrapped around? */ +@@ -305,10 +572,11 @@ static void be_tx_rate_update(struct be_adapter *adapter) + } + } + +-static void be_tx_stats_update(struct be_adapter *adapter, ++static void be_tx_stats_update(struct be_tx_obj *txo, + u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped) + { +- struct be_drvr_stats *stats = drvr_stats(adapter); ++ struct be_tx_stats *stats = tx_stats(txo); ++ + stats->be_tx_reqs++; + stats->be_tx_wrbs += wrb_cnt; + stats->be_tx_bytes += copied; +@@ -318,7 +586,8 @@ static void be_tx_stats_update(struct be_adapter *adapter, + } + + /* Determine number of WRB entries needed to xmit data in an skb */ +-static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy) ++static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb, ++ bool *dummy) + { + int cnt = (skb->len > skb->data_len); + +@@ -326,12 +595,13 @@ static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy) + + /* to account for hdr wrb */ + cnt++; +- if (cnt & 1) { ++ if (lancer_chip(adapter) || !(cnt & 1)) { ++ *dummy = false; ++ } else { + /* add a dummy to make it an even num */ + cnt++; + *dummy = true; +- } else +- *dummy = false; ++ } + BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT); + return cnt; + } +@@ -343,17 +613,31 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) + wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; + } + +-static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, +- bool vlan, u32 wrb_cnt, u32 len) ++static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, ++ struct sk_buff *skb, u32 wrb_cnt, u32 len) + { ++ u16 vlan_tag = 0; ++ + memset(hdr, 0, sizeof(*hdr)); + + AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1); + +- if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) { ++ if (skb_is_gso(skb)) { + AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1); + AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss, + hdr, skb_shinfo(skb)->gso_size); ++ if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) ++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1); ++ ++ if (lancer_A0_chip(adapter)) { ++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1); ++ if (is_tcp_pkt(skb)) ++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, ++ tcpcs, hdr, 1); ++ else if (is_udp_pkt(skb)) ++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, ++ udpcs, hdr, 1); ++ } + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (is_tcp_pkt(skb)) + AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1); +@@ -361,10 +645,10 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, + AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1); + } + +- if (vlan && vlan_tx_tag_present(skb)) { ++ if (adapter->vlan_grp && vlan_tx_tag_present(skb)) { + AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); +- AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, +- hdr, vlan_tx_tag_get(skb)); ++ vlan_tag = be_get_tx_vlan_tag(adapter, skb); ++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); + } + + AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1); +@@ -374,14 +658,13 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, + } + + +-static int make_tx_wrbs(struct be_adapter *adapter, ++static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, + struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb) + { +- u64 busaddr; +- u32 i, copied = 0; ++ dma_addr_t busaddr; ++ int i, copied = 0; + struct pci_dev *pdev = adapter->pdev; + struct sk_buff *first_skb = skb; +- struct be_queue_info *txq = &adapter->tx_obj.q; + struct be_eth_wrb *wrb; + struct be_eth_hdr_wrb *hdr; + +@@ -389,15 +672,11 @@ static int make_tx_wrbs(struct be_adapter *adapter, + atomic_add(wrb_cnt, &txq->used); + queue_head_inc(txq); + +- if (skb_dma_map(&pdev->dev, skb, DMA_TO_DEVICE)) { +- dev_err(&pdev->dev, "TX DMA mapping failed\n"); +- return 0; +- } +- + if (skb->len > skb->data_len) { +- int len = skb->len - skb->data_len; ++ int len = skb_headlen(skb); ++ busaddr = pci_map_single(pdev, skb->data, len, ++ PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); +- busaddr = skb_shinfo(skb)->dma_head; + wrb_fill(wrb, busaddr, len); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); +@@ -407,8 +686,9 @@ static int make_tx_wrbs(struct be_adapter *adapter, + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; +- +- busaddr = skb_shinfo(skb)->dma_maps[i]; ++ busaddr = pci_map_page(pdev, frag->page, ++ frag->page_offset, ++ frag->size, PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, frag->size); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); +@@ -423,8 +703,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, + queue_head_inc(txq); + } + +- wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false, +- wrb_cnt, copied); ++ wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied); + be_dws_cpu_to_le(hdr, sizeof(*hdr)); + + return copied; +@@ -434,19 +713,70 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_tx_obj *tx_obj = &adapter->tx_obj; +- struct be_queue_info *txq = &tx_obj->q; ++ struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; ++ struct be_queue_info *txq = &txo->q; + u32 wrb_cnt = 0, copied = 0; + u32 start = txq->head; + bool dummy_wrb, stopped = false; + +- wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb); ++ if (unlikely((skb_shinfo(skb)->gso_segs > 1) && ++ skb_shinfo(skb)->gso_size && is_ipv6_ext_hdr(skb))) { ++ tx_stats(txo)->be_ipv6_ext_hdr_tx_drop++; ++ goto tx_drop; ++ } + +- copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb); ++ /* If the skb is a large pkt forwarded to this interface ++ * after being LRO'd on another interface, drop the pkt. ++ * HW cannot handle such pkts. LRO must be disabled when ++ * using the server as a router. ++ */ ++ if (!skb_is_gso(skb)) { ++ int eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? ++ VLAN_ETH_HLEN : ETH_HLEN; ++ ++ if ((skb->len - eth_hdr_len) > adapter->netdev->mtu) ++ goto tx_drop; ++ } ++ ++ /* The ASIC is calculating checksum for Vlan tagged pkts ++ * though CSO is disabled. ++ * To work around this, insert the Vlan tag in the driver ++ * and donot set the vlan bit, cso bit in the Tx WRB. ++ */ ++ if (unlikely(vlan_tx_tag_present(skb) && ++ ((skb->ip_summed != CHECKSUM_PARTIAL) || (skb->len <= 60)))) { ++ /* Bug 28694: Don't embed the host VLAN tag in SKB ++ * when UMC mode enabled on that interface ++ */ ++ if (!(adapter->function_mode & UMC_ENABLED)) { ++ skb = skb_share_check(skb, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ goto tx_drop; ++ ++ skb = be_vlan_put_tag(skb, ++ be_get_tx_vlan_tag(adapter, skb)); ++ if (unlikely(!skb)) ++ goto tx_drop; ++ ++ be_reset_skb_tx_vlan(skb); ++ } ++ } ++ ++ /* Bug 12422: the stack can send us skbs with length more than 65535 ++ * BE cannot handle such requests. Hack the extra data out and drop it. ++ */ ++ if (skb->len > 65535) { ++ int err = __pskb_trim(skb, 65535); ++ BUG_ON(err); ++ } ++ ++ wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); ++ ++ copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); + if (copied) { + /* record the sent skb in the sent_skb table */ +- BUG_ON(tx_obj->sent_skb_list[start]); +- tx_obj->sent_skb_list[start] = skb; ++ BUG_ON(txo->sent_skb_list[start]); ++ txo->sent_skb_list[start] = skb; + + /* Ensure txq has space for the next skb; Else stop the queue + * *BEFORE* ringing the tx doorbell, so that we serialze the +@@ -454,16 +784,21 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, + */ + if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= + txq->len) { +- netif_stop_queue(netdev); ++ netif_stop_subqueue(netdev, skb_get_queue_mapping(skb)); + stopped = true; + } + + be_txq_notify(adapter, txq->id, wrb_cnt); + +- be_tx_stats_update(adapter, wrb_cnt, copied, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) ++ netdev->trans_start = jiffies; ++#endif ++ ++ be_tx_stats_update(txo, wrb_cnt, copied, + skb_shinfo(skb)->gso_segs, stopped); + } else { + txq->head = start; ++tx_drop: + dev_kfree_skb_any(skb); + } + return NETDEV_TX_OK; +@@ -473,10 +808,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) + { + struct be_adapter *adapter = netdev_priv(netdev); + if (new_mtu < BE_MIN_MTU || +- new_mtu > BE_MAX_JUMBO_FRAME_SIZE) { ++ new_mtu > (BE_MAX_JUMBO_FRAME_SIZE - ++ (ETH_HLEN + ETH_FCS_LEN))) { + dev_info(&adapter->pdev->dev, + "MTU must be between %d and %d bytes\n", +- BE_MIN_MTU, BE_MAX_JUMBO_FRAME_SIZE); ++ BE_MIN_MTU, ++ (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN))); + return -EINVAL; + } + dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n", +@@ -486,17 +823,19 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) + } + + /* +- * if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured, +- * program them in BE. If more than BE_NUM_VLANS_SUPPORTED are configured, +- * set the BE in promiscuous VLAN mode. ++ * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE. ++ * If the user configures more, place BE in vlan promiscuous mode. + */ +-static int be_vid_config(struct be_adapter *adapter) ++static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) + { + u16 vtag[BE_NUM_VLANS_SUPPORTED]; + u16 ntags = 0, i; +- int status; ++ int status = 0; + +- if (adapter->num_vlans <= BE_NUM_VLANS_SUPPORTED) { ++ /* No need to change the VLAN state if the I/F is in promiscous */ ++ if (adapter->promiscuous) ++ return 0; ++ if (adapter->vlans_added <= adapter->max_vlans) { + /* Construct VLAN Table to give to HW */ + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + if (adapter->vlan_tag[i]) { +@@ -504,47 +843,46 @@ static int be_vid_config(struct be_adapter *adapter) + ntags++; + } + } +- status = be_cmd_vlan_config(adapter, adapter->if_handle, +- vtag, ntags, 1, 0); ++ /* Send command only if there is something to be programmed */ ++ if (ntags) ++ status = be_cmd_vlan_config(adapter, adapter->if_handle, ++ vtag, ntags, 1, 0); + } else { + status = be_cmd_vlan_config(adapter, adapter->if_handle, +- NULL, 0, 1, 1); ++ NULL, 0, 1, 1); + } ++ + return status; + } + + static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *rx_eq = &adapter->rx_eq; +- struct be_eq_obj *tx_eq = &adapter->tx_eq; + +- be_eq_notify(adapter, rx_eq->q.id, false, false, 0); +- be_eq_notify(adapter, tx_eq->q.id, false, false, 0); + adapter->vlan_grp = grp; +- be_eq_notify(adapter, rx_eq->q.id, true, false, 0); +- be_eq_notify(adapter, tx_eq->q.id, true, false, 0); + } + + static void be_vlan_add_vid(struct net_device *netdev, u16 vid) + { + struct be_adapter *adapter = netdev_priv(netdev); + +- adapter->num_vlans++; ++ adapter->vlans_added++; ++ + adapter->vlan_tag[vid] = 1; +- +- be_vid_config(adapter); ++ if (adapter->vlans_added <= (adapter->max_vlans + 1)) ++ be_vid_config(adapter, false, 0); + } + + static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) + { + struct be_adapter *adapter = netdev_priv(netdev); + +- adapter->num_vlans--; +- adapter->vlan_tag[vid] = 0; +- ++ adapter->vlans_added--; + vlan_group_set_device(adapter->vlan_grp, vid, NULL); +- be_vid_config(adapter); ++ ++ adapter->vlan_tag[vid] = 0; ++ if (adapter->vlans_added <= adapter->max_vlans) ++ be_vid_config(adapter, false, 0); + } + + static void be_set_multicast_list(struct net_device *netdev) +@@ -552,7 +890,7 @@ static void be_set_multicast_list(struct net_device *netdev) + struct be_adapter *adapter = netdev_priv(netdev); + + if (netdev->flags & IFF_PROMISC) { +- be_cmd_promiscuous_config(adapter, adapter->port_num, 1); ++ be_cmd_rx_filter(adapter, IFF_PROMISC, ON); + adapter->promiscuous = true; + goto done; + } +@@ -560,81 +898,244 @@ static void be_set_multicast_list(struct net_device *netdev) + /* BE was previously in promiscous mode; disable it */ + if (adapter->promiscuous) { + adapter->promiscuous = false; +- be_cmd_promiscuous_config(adapter, adapter->port_num, 0); ++ be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); ++ ++ if (adapter->vlans_added) ++ be_vid_config(adapter, false, 0); + } + +- if (netdev->flags & IFF_ALLMULTI) { +- be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0); ++ /* Enable multicast promisc if num configured exceeds what we support */ ++ if (netdev->flags & IFF_ALLMULTI || ++ netdev_mc_count(netdev) > BE_MAX_MC) { ++ be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON); + goto done; + } + +- be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list, +- netdev->mc_count); ++ be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); + done: + return; + } + +-static void be_rx_rate_update(struct be_adapter *adapter) ++#ifdef HAVE_SRIOV_CONFIG ++static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) + { +- struct be_drvr_stats *stats = drvr_stats(adapter); ++ struct be_adapter *adapter = netdev_priv(netdev); ++ int status; ++ ++ if (adapter->num_vfs == 0) ++ return -EPERM; ++ ++ if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs)) ++ return -EINVAL; ++ ++ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) ++ status = be_cmd_pmac_del(adapter, ++ adapter->vf_cfg[vf].vf_if_handle, ++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ ++ status = be_cmd_pmac_add(adapter, mac, ++ adapter->vf_cfg[vf].vf_if_handle, ++ &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ ++ if (status) ++ dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", ++ mac, vf); ++ else ++ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); ++ ++ return status; ++} ++ ++static int be_get_vf_config(struct net_device *netdev, int vf, ++ struct ifla_vf_info *vi) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ ++ if (adapter->num_vfs == 0) ++ return -EPERM; ++ ++ if (vf >= adapter->num_vfs) ++ return -EINVAL; ++ ++ vi->vf = vf; ++ vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate; ++ vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag & VLAN_VID_MASK; ++ vi->qos = adapter->vf_cfg[vf].vf_vlan_tag >> VLAN_PRIO_SHIFT; ++ memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN); ++ ++ return 0; ++} ++ ++/* ++ * Entry point to configure vlan behavior for a VF. ++ * 1. By default a VF is vlan Challenged. ++ * 2. It may or may not have Transparent Tagging enabled. ++ * 3. Vlan privilege for a VF can be toggled using special VID 4095. ++ * 4. When removing the Vlan privilege for a VF there is no need set default vid ++ * 5. Transparent Tagging configured for a VF resets its Vlan privilege ++ * 6. To disable the current Transparet Tagging for a VF: ++ * 6a. run the last iproute command with vlan set to 0. ++ * 6b. programing the default vid will disable Transparent Tagging in ARM/ASIC ++ */ ++static int be_set_vf_vlan(struct net_device *netdev, ++ int vf, u16 vlan, u8 qos) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ int status = 0; ++ u32 en = 0; ++ ++ if (adapter->num_vfs == 0) ++ return -EPERM; ++ ++ if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7)) ++ return -EINVAL; ++ ++ status = be_cmd_get_fn_privileges(adapter, &en, vf + 1); ++ if (status) ++ goto sts; ++ ++ if (vlan == 4095) { ++ if (en & BE_PRIV_FILTMGMT) { ++ /* Knock off filtering privileges */ ++ en &= ~BE_PRIV_FILTMGMT; ++ } else { ++ en |= BE_PRIV_FILTMGMT; ++ /* Transparent Tagging is currently enabled, Reset it */ ++ if (adapter->vf_cfg[vf].vf_vlan_tag) { ++ adapter->vf_cfg[vf].vf_vlan_tag = 0; ++ vlan = adapter->vf_cfg[vf].vf_def_vid; ++ be_cmd_set_hsw_config(adapter, vlan, vf + 1, ++ adapter->vf_cfg[vf].vf_if_handle); ++ } ++ } ++ ++ adapter->vf_cfg[vf].vf_vlan_tag = 0; ++ status = be_cmd_set_fn_privileges(adapter, en, NULL, vf + 1); ++ ++ goto sts; ++ } ++ ++ if (vlan || qos) { ++ if (en & BE_PRIV_FILTMGMT) { ++ /* Check privilege and reset it to default */ ++ en &= ~BE_PRIV_FILTMGMT; ++ be_cmd_set_fn_privileges(adapter, en, NULL, vf + 1); ++ } ++ ++ vlan |= qos << VLAN_PRIO_SHIFT; ++ if (adapter->vf_cfg[vf].vf_vlan_tag != vlan) { ++ /* If this is new value, program it. Else skip. */ ++ adapter->vf_cfg[vf].vf_vlan_tag = vlan; ++ ++ status = be_cmd_set_hsw_config(adapter, vlan, ++ vf + 1, adapter->vf_cfg[vf].vf_if_handle); ++ } ++ ++ } else { ++ /* Reset Transparent Vlan Tagging. */ ++ adapter->vf_cfg[vf].vf_vlan_tag = 0; ++ vlan = adapter->vf_cfg[vf].vf_def_vid; ++ status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, ++ adapter->vf_cfg[vf].vf_if_handle); ++ } ++ ++sts: ++ if (status) ++ dev_info(&adapter->pdev->dev, ++ "VLAN %d config on VF %d failed\n", vlan, vf); ++ return status; ++} ++ ++static int be_set_vf_tx_rate(struct net_device *netdev, ++ int vf, int rate) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ int status = 0; ++ ++ if (adapter->num_vfs == 0) ++ return -EPERM; ++ ++ if ((vf >= adapter->num_vfs) || (rate < 0)) ++ return -EINVAL; ++ ++ if (rate > 10000) ++ rate = 10000; ++ ++ adapter->vf_cfg[vf].vf_tx_rate = rate; ++ status = be_cmd_set_qos(adapter, rate / 10, vf + 1); ++ ++ if (status) ++ dev_info(&adapter->pdev->dev, ++ "tx rate %d on VF %d failed\n", rate, vf); ++ return status; ++} ++#endif /* HAVE_SRIOV_CONFIG */ ++ ++static void be_rx_rate_update(struct be_rx_obj *rxo) ++{ ++ struct be_rx_stats *stats = &rxo->stats; + ulong now = jiffies; + + /* Wrapped around */ +- if (time_before(now, stats->be_rx_jiffies)) { +- stats->be_rx_jiffies = now; ++ if (time_before(now, stats->rx_jiffies)) { ++ stats->rx_jiffies = now; + return; + } + + /* Update the rate once in two seconds */ +- if ((now - stats->be_rx_jiffies) < 2 * HZ) ++ if ((now - stats->rx_jiffies) < 2 * HZ) + return; + +- stats->be_rx_rate = be_calc_rate(stats->be_rx_bytes +- - stats->be_rx_bytes_prev, +- now - stats->be_rx_jiffies); +- stats->be_rx_jiffies = now; +- stats->be_rx_bytes_prev = stats->be_rx_bytes; ++ stats->rx_rate = be_calc_rate(stats->rx_bytes - stats->rx_bytes_prev, ++ now - stats->rx_jiffies); ++ stats->rx_jiffies = now; ++ stats->rx_bytes_prev = stats->rx_bytes; + } + +-static void be_rx_stats_update(struct be_adapter *adapter, +- u32 pktsize, u16 numfrags) ++static void be_rx_stats_update(struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) + { +- struct be_drvr_stats *stats = drvr_stats(adapter); ++ struct be_rx_stats *stats = &rxo->stats; + +- stats->be_rx_compl++; +- stats->be_rx_frags += numfrags; +- stats->be_rx_bytes += pktsize; +- stats->be_rx_pkts++; ++ stats->rx_compl++; ++ stats->rx_frags += rxcp->num_rcvd; ++ stats->rx_bytes += rxcp->pkt_size; ++ stats->rx_pkts++; ++ if (rxcp->pkt_type == BE_MULTICAST_PACKET) ++ stats->rx_mcast_pkts++; ++ if (rxcp->err) ++ stats->rxcp_err++; + } + +-static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso) ++static inline bool csum_passed(struct be_rx_compl_info *rxcp) + { +- u8 l4_cksm, ip_version, ipcksm, tcpf = 0, udpf = 0, ipv6_chk; +- +- l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp); +- ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp); +- ip_version = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp); +- if (ip_version) { +- tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp); +- udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp); +- } +- ipv6_chk = (ip_version && (tcpf || udpf)); +- +- return ((l4_cksm && ipv6_chk && ipcksm) && cso) ? false : true; ++ /* L4 checksum is not reliable for non TCP/UDP packets. ++ * Also ignore ipcksm for ipv6 pkts */ ++ return (rxcp->tcpf || rxcp->udpf) && rxcp->l4_csum && ++ (rxcp->ip_csum || rxcp->ipv6); + } + + static struct be_rx_page_info * +-get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) ++get_rx_page_info(struct be_adapter *adapter, struct be_rx_obj *rxo, ++ u16 frag_idx) + { + struct be_rx_page_info *rx_page_info; +- struct be_queue_info *rxq = &adapter->rx_obj.q; ++ struct be_queue_info *rxq = &rxo->q; + +- rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx]; +- BUG_ON(!rx_page_info->page); ++ rx_page_info = &rxo->page_info_tbl[frag_idx]; ++ if (!rx_page_info->page) { ++ printk(KERN_EMERG "curr_idx=%d prev_dix=%d rxq->head=%d\n", ++ frag_idx, rxo->prev_frag_idx, rxq->head); ++ BUG_ON(!rx_page_info->page); ++ } + +- if (rx_page_info->last_page_user) ++ if (rx_page_info->last_page_user) { + pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus), + adapter->big_page_size, PCI_DMA_FROMDEVICE); ++ rx_page_info->last_page_user = false; ++ } ++ ++ rxo->prev_frag_idx = frag_idx; + + atomic_dec(&rxq->used); + return rx_page_info; +@@ -642,20 +1143,26 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) + + /* Throwaway the data in the Rx completion */ + static void be_rx_compl_discard(struct be_adapter *adapter, +- struct be_eth_rx_compl *rxcp) ++ struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) + { +- struct be_queue_info *rxq = &adapter->rx_obj.q; ++ struct be_queue_info *rxq = &rxo->q; + struct be_rx_page_info *page_info; +- u16 rxq_idx, i, num_rcvd; ++ u16 i; ++ bool oob_error; ++ u16 num_rcvd = rxcp->num_rcvd; + +- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); +- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); ++ oob_error = lancer_A0_chip(adapter) && rxcp->err; ++ ++ /* In case of OOB error num_rcvd will be 1 more than actual */ ++ if (oob_error && num_rcvd) ++ num_rcvd -= 1; + + for (i = 0; i < num_rcvd; i++) { +- page_info = get_rx_page_info(adapter, rxq_idx); ++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); + put_page(page_info->page); + memset(page_info, 0, sizeof(*page_info)); +- index_inc(&rxq_idx, rxq->len); ++ index_inc(&rxcp->rxq_idx, rxq->len); + } + } + +@@ -663,29 +1170,24 @@ static void be_rx_compl_discard(struct be_adapter *adapter, + * skb_fill_rx_data forms a complete skb for an ether frame + * indicated by rxcp. + */ +-static void skb_fill_rx_data(struct be_adapter *adapter, +- struct sk_buff *skb, struct be_eth_rx_compl *rxcp) ++static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, ++ struct sk_buff *skb, struct be_rx_compl_info *rxcp) + { +- struct be_queue_info *rxq = &adapter->rx_obj.q; ++ struct be_queue_info *rxq = &rxo->q; + struct be_rx_page_info *page_info; +- u16 rxq_idx, i, num_rcvd, j; +- u32 pktsize, hdr_len, curr_frag_len, size; ++ u16 i, j; ++ u16 hdr_len, curr_frag_len, remaining; + u8 *start; + +- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); +- pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); +- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); +- +- page_info = get_rx_page_info(adapter, rxq_idx); +- ++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); + start = page_address(page_info->page) + page_info->page_offset; + prefetch(start); + + /* Copy data in the first descriptor of this completion */ +- curr_frag_len = min(pktsize, rx_frag_size); ++ curr_frag_len = min(rxcp->pkt_size, rx_frag_size); + + /* Copy the header portion into skb_data */ +- hdr_len = min((u32)BE_HDR_LEN, curr_frag_len); ++ hdr_len = min(BE_HDR_LEN, curr_frag_len); + memcpy(skb->data, start, hdr_len); + skb->len = curr_frag_len; + if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */ +@@ -702,21 +1204,19 @@ static void skb_fill_rx_data(struct be_adapter *adapter, + skb->data_len = curr_frag_len - hdr_len; + skb->tail += hdr_len; + } +- memset(page_info, 0, sizeof(*page_info)); ++ page_info->page = NULL; + +- if (pktsize <= rx_frag_size) { +- BUG_ON(num_rcvd != 1); +- goto done; ++ if (rxcp->pkt_size <= rx_frag_size) { ++ BUG_ON(rxcp->num_rcvd != 1); ++ return; + } + + /* More frags present for this completion */ +- size = pktsize; +- for (i = 1, j = 0; i < num_rcvd; i++) { +- size -= curr_frag_len; +- index_inc(&rxq_idx, rxq->len); +- page_info = get_rx_page_info(adapter, rxq_idx); +- +- curr_frag_len = min(size, rx_frag_size); ++ index_inc(&rxcp->rxq_idx, rxq->len); ++ remaining = rxcp->pkt_size - curr_frag_len; ++ for (i = 1, j = 0; i < rxcp->num_rcvd; i++) { ++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); ++ curr_frag_len = min(remaining, rx_frag_size); + + /* Coalesce all frags from the same physical page in one slot */ + if (page_info->page_offset == 0) { +@@ -735,99 +1235,122 @@ static void skb_fill_rx_data(struct be_adapter *adapter, + skb->len += curr_frag_len; + skb->data_len += curr_frag_len; + +- memset(page_info, 0, sizeof(*page_info)); ++ remaining -= curr_frag_len; ++ index_inc(&rxcp->rxq_idx, rxq->len); ++ page_info->page = NULL; + } + BUG_ON(j > MAX_SKB_FRAGS); +- +-done: +- be_rx_stats_update(adapter, pktsize, num_rcvd); +- return; + } + +-/* Process the RX completion indicated by rxcp when GRO is disabled */ ++/* Process the RX completion indicated by rxcp when LRO is disabled */ + static void be_rx_compl_process(struct be_adapter *adapter, +- struct be_eth_rx_compl *rxcp) ++ struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) + { + struct sk_buff *skb; +- u32 vlanf, vid; +- u8 vtm; + +- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); +- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp); +- +- /* vlanf could be wrongly set in some cards. +- * ignore if vtm is not set */ +- if ((adapter->cap == 0x400) && !vtm) +- vlanf = 0; +- +- skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN); +- if (!skb) { ++ skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); ++ if (unlikely(!skb)) { + if (net_ratelimit()) + dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); +- be_rx_compl_discard(adapter, rxcp); ++ be_rx_compl_discard(adapter, rxo, rxcp); + return; + } + +- skb_reserve(skb, NET_IP_ALIGN); ++ skb_fill_rx_data(adapter, rxo, skb, rxcp); + +- skb_fill_rx_data(adapter, skb, rxcp); +- +- if (do_pkt_csum(rxcp, adapter->rx_csum)) +- skb->ip_summed = CHECKSUM_NONE; +- else ++ if (likely(adapter->rx_csum && csum_passed(rxcp))) + skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; + + skb->truesize = skb->len + sizeof(struct sk_buff); ++ if (unlikely(rxcp->vlanf) && ++ unlikely(!vlan_configured(adapter))) { ++ __vlan_put_tag(skb, rxcp->vlan_tag); ++ } + skb->protocol = eth_type_trans(skb, adapter->netdev); + skb->dev = adapter->netdev; + +- if (vlanf) { +- if (!adapter->vlan_grp || adapter->num_vlans == 0) { +- kfree_skb(skb); +- return; +- } +- vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); +- vid = be16_to_cpu(vid); +- vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid); +- } else { ++ if (unlikely(rxcp->vlanf) && ++ vlan_configured(adapter)) ++ vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, ++ rxcp->vlan_tag); ++ else + netif_receive_skb(skb); ++ ++ return; ++} ++ ++/* Process the RX completion indicated by rxcp when LRO is enabled */ ++static void be_rx_compl_process_lro(struct be_adapter *adapter, ++ struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) ++{ ++ struct be_rx_page_info *page_info; ++ struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME]; ++ struct be_queue_info *rxq = &rxo->q; ++ u16 remaining, curr_frag_len; ++ u16 i, j; ++ ++ remaining = rxcp->pkt_size; ++ for (i = 0, j = -1; i < rxcp->num_rcvd; i++) { ++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); ++ ++ curr_frag_len = min(remaining, rx_frag_size); ++ ++ /* Coalesce all frags from the same physical page in one slot */ ++ if (i == 0 || page_info->page_offset == 0) { ++ /* First frag or Fresh page */ ++ j++; ++ rx_frags[j].page = page_info->page; ++ rx_frags[j].page_offset = page_info->page_offset; ++ rx_frags[j].size = 0; ++ } else { ++ put_page(page_info->page); ++ } ++ rx_frags[j].size += curr_frag_len; ++ ++ remaining -= curr_frag_len; ++ index_inc(&rxcp->rxq_idx, rxq->len); ++ memset(page_info, 0, sizeof(*page_info)); ++ } ++ BUG_ON(j > MAX_SKB_FRAGS); ++ ++ if (likely(!rxcp->vlanf)) { ++ lro_receive_frags(&rxo->lro_mgr, rx_frags, rxcp->pkt_size, ++ rxcp->pkt_size, NULL, 0); ++ } else { ++ lro_vlan_hwaccel_receive_frags(&rxo->lro_mgr, rx_frags, ++ rxcp->pkt_size, rxcp->pkt_size, adapter->vlan_grp, ++ rxcp->vlan_tag, NULL, 0); + } + + return; + } + + /* Process the RX completion indicated by rxcp when GRO is enabled */ +-static void be_rx_compl_process_gro(struct be_adapter *adapter, +- struct be_eth_rx_compl *rxcp) ++void be_rx_compl_process_gro(struct be_adapter *adapter, ++ struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) + { ++#ifdef NETIF_F_GRO + struct be_rx_page_info *page_info; + struct sk_buff *skb = NULL; +- struct be_queue_info *rxq = &adapter->rx_obj.q; +- struct be_eq_obj *eq_obj = &adapter->rx_eq; +- u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; +- u16 i, rxq_idx = 0, vid, j; +- u8 vtm; +- +- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); +- pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); +- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); +- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); +- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp); +- +- /* vlanf could be wrongly set in some cards. +- * ignore if vtm is not set */ +- if ((adapter->cap == 0x400) && !vtm) +- vlanf = 0; ++ struct be_queue_info *rxq = &rxo->q; ++ struct be_eq_obj *eq_obj = &rxo->rx_eq; ++ u16 remaining, curr_frag_len; ++ u16 i, j; + + skb = napi_get_frags(&eq_obj->napi); + if (!skb) { +- be_rx_compl_discard(adapter, rxcp); ++ be_rx_compl_discard(adapter, rxo, rxcp); + return; + } + +- remaining = pkt_size; +- for (i = 0, j = -1; i < num_rcvd; i++) { +- page_info = get_rx_page_info(adapter, rxq_idx); ++ remaining = rxcp->pkt_size; ++ for (i = 0, j = -1; i < rxcp->num_rcvd; i++) { ++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); + + curr_frag_len = min(remaining, rx_frag_size); + +@@ -845,55 +1368,129 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, + skb_shinfo(skb)->frags[j].size += curr_frag_len; + + remaining -= curr_frag_len; +- index_inc(&rxq_idx, rxq->len); ++ index_inc(&rxcp->rxq_idx, rxq->len); + memset(page_info, 0, sizeof(*page_info)); + } + BUG_ON(j > MAX_SKB_FRAGS); + + skb_shinfo(skb)->nr_frags = j + 1; +- skb->len = pkt_size; +- skb->data_len = pkt_size; +- skb->truesize += pkt_size; ++ skb->len = rxcp->pkt_size; ++ skb->data_len = rxcp->pkt_size; ++ skb->truesize += rxcp->pkt_size; + skb->ip_summed = CHECKSUM_UNNECESSARY; + +- if (likely(!vlanf)) { ++ if (likely(!rxcp->vlanf)) + napi_gro_frags(&eq_obj->napi); +- } else { +- vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); +- vid = be16_to_cpu(vid); ++ else ++ vlan_gro_frags(&eq_obj->napi, ++ adapter->vlan_grp, rxcp->vlan_tag); ++#endif + +- if (!adapter->vlan_grp || adapter->num_vlans == 0) +- return; +- +- vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); +- } +- +- be_rx_stats_update(adapter, pkt_size, num_rcvd); + return; + } + +-static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) ++static void be_parse_rx_compl_v1(struct be_adapter *adapter, ++ struct be_eth_rx_compl *compl, ++ struct be_rx_compl_info *rxcp) + { +- struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq); ++ rxcp->pkt_size = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl); ++ rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtp, compl); ++ rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, err, compl); ++ rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tcpf, compl); ++ rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, udpf, compl); ++ rxcp->ip_csum = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ipcksm, compl); ++ rxcp->l4_csum = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl); ++ rxcp->ipv6 = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl); ++ rxcp->rxq_idx = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, fragndx, compl); ++ rxcp->num_rcvd = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); ++ rxcp->pkt_type = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); ++ if (rxcp->vlanf) { ++ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, ++ compl); ++ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ++ vlan_tag, compl); ++ } ++ rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl); ++} + +- if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0) ++static void be_parse_rx_compl_v0(struct be_adapter *adapter, ++ struct be_eth_rx_compl *compl, ++ struct be_rx_compl_info *rxcp) ++{ ++ rxcp->pkt_size = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl); ++ rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtp, compl); ++ rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, err, compl); ++ rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, tcpf, compl); ++ rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, udpf, compl); ++ rxcp->ip_csum = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ipcksm, compl); ++ rxcp->l4_csum = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl); ++ rxcp->ipv6 = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl); ++ rxcp->rxq_idx = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, fragndx, compl); ++ rxcp->num_rcvd = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); ++ rxcp->pkt_type = ++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); ++ if (rxcp->vlanf) { ++ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, ++ compl); ++ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ++ vlan_tag, compl); ++ } ++ rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl); ++} ++ ++static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) ++{ ++ struct be_eth_rx_compl *compl = queue_tail_node(&rxo->cq); ++ struct be_rx_compl_info *rxcp = &rxo->rxcp; ++ struct be_adapter *adapter = rxo->adapter; ++ ++ /* For checking the valid bit it is Ok to use either definition as the ++ * valid bit is at the same position in both v0 and v1 Rx compl */ ++ if (compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] == 0) + return NULL; + +- be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); ++ rmb(); ++ be_dws_le_to_cpu(compl, sizeof(*compl)); + +- queue_tail_inc(&adapter->rx_obj.cq); ++ if (adapter->be3_native) ++ be_parse_rx_compl_v1(adapter, compl, rxcp); ++ else ++ be_parse_rx_compl_v0(adapter, compl, rxcp); ++ ++ if (rxcp->vlanf) { ++ /* vlanf could be wrongly set in some cards. ++ * ignore if vtm is not set */ ++ if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm) ++ rxcp->vlanf = 0; ++ ++ if (!lancer_chip(adapter)) ++ rxcp->vlan_tag = swab16(rxcp->vlan_tag); ++ ++ if ((adapter->pvid == (rxcp->vlan_tag & VLAN_VID_MASK)) && ++ !adapter->vlan_tag[rxcp->vlan_tag]) ++ rxcp->vlanf = 0; ++ } ++ ++ /* As the compl has been parsed, reset it; we wont touch it again */ ++ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0; ++ ++ queue_tail_inc(&rxo->cq); + return rxcp; + } + +-/* To reset the valid bit, we need to reset the whole word as +- * when walking the queue the valid entries are little-endian +- * and invalid entries are host endian +- */ +-static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp) +-{ +- rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; +-} +- + static inline struct page *be_alloc_pages(u32 size) + { + gfp_t alloc_flags = GFP_ATOMIC; +@@ -907,11 +1504,12 @@ static inline struct page *be_alloc_pages(u32 size) + * Allocate a page, split it to fragments of size rx_frag_size and post as + * receive buffers to BE + */ +-static void be_post_rx_frags(struct be_adapter *adapter) ++static void be_post_rx_frags(struct be_rx_obj *rxo) + { +- struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl; +- struct be_rx_page_info *page_info = NULL; +- struct be_queue_info *rxq = &adapter->rx_obj.q; ++ struct be_adapter *adapter = rxo->adapter; ++ struct be_rx_page_info *page_info_tbl = rxo->page_info_tbl; ++ struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL; ++ struct be_queue_info *rxq = &rxo->q; + struct page *pagep = NULL; + struct be_eth_rx_d *rxd; + u64 page_dmaaddr = 0, frag_dmaaddr; +@@ -922,7 +1520,7 @@ static void be_post_rx_frags(struct be_adapter *adapter) + if (!pagep) { + pagep = be_alloc_pages(adapter->big_page_size); + if (unlikely(!pagep)) { +- drvr_stats(adapter)->be_ethrx_post_fail++; ++ rxo->stats.rx_post_fail++; + break; + } + page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0, +@@ -941,7 +1539,6 @@ static void be_post_rx_frags(struct be_adapter *adapter) + rxd = queue_head_node(rxq); + rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF); + rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr)); +- queue_head_inc(rxq); + + /* Any space left in the current big page for another frag? */ + if ((page_offset + rx_frag_size + rx_frag_size) > +@@ -949,17 +1546,24 @@ static void be_post_rx_frags(struct be_adapter *adapter) + pagep = NULL; + page_info->last_page_user = true; + } ++ ++ prev_page_info = page_info; ++ queue_head_inc(rxq); + page_info = &page_info_tbl[rxq->head]; + } + if (pagep) +- page_info->last_page_user = true; ++ prev_page_info->last_page_user = true; + ++ /* Ensure that posting buffers is the last thing done by this ++ * routine to avoid racing between rx bottom-half and ++ * be_worker (process) contexts. ++ */ + if (posted) { + atomic_add(posted, &rxq->used); + be_rxq_notify(adapter, rxq->id, posted); + } else if (atomic_read(&rxq->used) == 0) { + /* Let be_worker replenish when memory is available */ +- adapter->rx_post_starved = true; ++ rxo->rx_post_starved = true; + } + + return; +@@ -972,6 +1576,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) + if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) + return NULL; + ++ rmb(); + be_dws_le_to_cpu(txcp, sizeof(*txcp)); + + txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0; +@@ -980,11 +1585,14 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) + return txcp; + } + +-static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) ++static u16 be_tx_compl_process(struct be_adapter *adapter, ++ struct be_tx_obj *txo, u16 last_index) + { +- struct be_queue_info *txq = &adapter->tx_obj.q; +- struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; ++ struct be_queue_info *txq = &txo->q; ++ struct be_eth_wrb *wrb; ++ struct sk_buff **sent_skbs = txo->sent_skb_list; + struct sk_buff *sent_skb; ++ u64 busaddr; + u16 cur_index, num_wrbs = 0; + + cur_index = txq->tail; +@@ -992,15 +1600,31 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) + BUG_ON(!sent_skb); + sent_skbs[cur_index] = NULL; + +- do { ++ wrb = queue_tail_node(txq); ++ be_dws_le_to_cpu(wrb, sizeof(*wrb)); ++ busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; ++ if (busaddr != 0) { ++ pci_unmap_single(adapter->pdev, busaddr, ++ wrb->frag_len, PCI_DMA_TODEVICE); ++ } ++ num_wrbs++; ++ queue_tail_inc(txq); ++ ++ while (cur_index != last_index) { + cur_index = txq->tail; ++ wrb = queue_tail_node(txq); ++ be_dws_le_to_cpu(wrb, sizeof(*wrb)); ++ busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; ++ if (busaddr != 0) { ++ pci_unmap_page(adapter->pdev, busaddr, ++ wrb->frag_len, PCI_DMA_TODEVICE); ++ } + num_wrbs++; + queue_tail_inc(txq); +- } while (cur_index != last_index); ++ } + +- atomic_sub(num_wrbs, &txq->used); +- skb_dma_unmap(&adapter->pdev->dev, sent_skb, DMA_TO_DEVICE); + kfree_skb(sent_skb); ++ return num_wrbs; + } + + static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) +@@ -1010,13 +1634,15 @@ static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) + if (!eqe->evt) + return NULL; + ++ rmb(); + eqe->evt = le32_to_cpu(eqe->evt); + queue_tail_inc(&eq_obj->q); + return eqe; + } + + static int event_handle(struct be_adapter *adapter, +- struct be_eq_obj *eq_obj) ++ struct be_eq_obj *eq_obj, ++ bool rearm) + { + struct be_eq_entry *eqe; + u16 num = 0; +@@ -1029,7 +1655,10 @@ static int event_handle(struct be_adapter *adapter, + /* Deal with any spurious interrupts that come + * without events + */ +- be_eq_notify(adapter, eq_obj->q.id, true, true, num); ++ if (!num) ++ rearm = true; ++ ++ be_eq_notify(adapter, eq_obj->q.id, rearm, true, num); + if (num) + napi_schedule(&eq_obj->napi); + +@@ -1053,49 +1682,55 @@ static void be_eq_clean(struct be_adapter *adapter, + be_eq_notify(adapter, eq_obj->q.id, false, true, num); + } + +-static void be_rx_q_clean(struct be_adapter *adapter) ++static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo) + { + struct be_rx_page_info *page_info; +- struct be_queue_info *rxq = &adapter->rx_obj.q; +- struct be_queue_info *rx_cq = &adapter->rx_obj.cq; +- struct be_eth_rx_compl *rxcp; ++ struct be_queue_info *rxq = &rxo->q; ++ struct be_queue_info *rx_cq = &rxo->cq; ++ struct be_rx_compl_info *rxcp; + u16 tail; + + /* First cleanup pending rx completions */ +- while ((rxcp = be_rx_compl_get(adapter)) != NULL) { +- be_rx_compl_discard(adapter, rxcp); +- be_rx_compl_reset(rxcp); ++ while ((rxcp = be_rx_compl_get(rxo)) != NULL) { ++ be_rx_compl_discard(adapter, rxo, rxcp); + be_cq_notify(adapter, rx_cq->id, true, 1); + } + + /* Then free posted rx buffer that were not used */ + tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; + for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { +- page_info = get_rx_page_info(adapter, tail); ++ page_info = get_rx_page_info(adapter, rxo, tail); + put_page(page_info->page); + memset(page_info, 0, sizeof(*page_info)); + } + BUG_ON(atomic_read(&rxq->used)); ++ rxq->tail = rxq->head = 0; + } + +-static void be_tx_compl_clean(struct be_adapter *adapter) ++static void be_tx_compl_clean(struct be_adapter *adapter, ++ struct be_tx_obj *txo) + { +- struct be_queue_info *tx_cq = &adapter->tx_obj.cq; +- struct be_queue_info *txq = &adapter->tx_obj.q; ++ struct be_queue_info *tx_cq = &txo->cq; ++ struct be_queue_info *txq = &txo->q; + struct be_eth_tx_compl *txcp; +- u16 end_idx, cmpl = 0, timeo = 0; ++ u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; ++ struct sk_buff **sent_skbs = txo->sent_skb_list; ++ struct sk_buff *sent_skb; ++ bool dummy_wrb; + + /* Wait for a max of 200ms for all the tx-completions to arrive. */ + do { + while ((txcp = be_tx_compl_get(tx_cq))) { + end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, + wrb_index, txcp); +- be_tx_compl_process(adapter, end_idx); ++ num_wrbs += be_tx_compl_process(adapter, txo, end_idx); + cmpl++; + } + if (cmpl) { + be_cq_notify(adapter, tx_cq->id, false, cmpl); ++ atomic_sub(num_wrbs, &txq->used); + cmpl = 0; ++ num_wrbs = 0; + } + + if (atomic_read(&txq->used) == 0 || ++timeo > 200) +@@ -1107,6 +1742,17 @@ static void be_tx_compl_clean(struct be_adapter *adapter) + if (atomic_read(&txq->used)) + dev_err(&adapter->pdev->dev, "%d pending tx-completions\n", + atomic_read(&txq->used)); ++ ++ /* free posted tx for which compls will never arrive */ ++ while (atomic_read(&txq->used)) { ++ sent_skb = sent_skbs[txq->tail]; ++ end_idx = txq->tail; ++ index_adv(&end_idx, ++ wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1, ++ txq->len); ++ num_wrbs = be_tx_compl_process(adapter, txo, end_idx); ++ atomic_sub(num_wrbs, &txq->used); ++ } + } + + static void be_mcc_queues_destroy(struct be_adapter *adapter) +@@ -1145,8 +1791,9 @@ static int be_mcc_queues_create(struct be_adapter *adapter) + goto mcc_cq_destroy; + + /* Ask BE to create MCC queue */ +- if (be_cmd_mccq_create(adapter, q, cq)) ++ if (be_cmd_mccq_create(adapter, q, cq)) { + goto mcc_q_free; ++ } + + return 0; + +@@ -1163,16 +1810,20 @@ err: + static void be_tx_queues_destroy(struct be_adapter *adapter) + { + struct be_queue_info *q; ++ struct be_tx_obj *txo; ++ u8 i; + +- q = &adapter->tx_obj.q; +- if (q->created) +- be_cmd_q_destroy(adapter, q, QTYPE_TXQ); +- be_queue_free(adapter, q); ++ for_all_tx_queues(adapter, txo, i) { ++ q = &txo->q; ++ if (q->created) ++ be_cmd_q_destroy(adapter, q, QTYPE_TXQ); ++ be_queue_free(adapter, q); + +- q = &adapter->tx_obj.cq; +- if (q->created) +- be_cmd_q_destroy(adapter, q, QTYPE_CQ); +- be_queue_free(adapter, q); ++ q = &txo->cq; ++ if (q->created) ++ be_cmd_q_destroy(adapter, q, QTYPE_CQ); ++ be_queue_free(adapter, q); ++ } + + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->tx_eq); +@@ -1183,168 +1834,210 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) + be_queue_free(adapter, q); + } + ++/* One TX event queue is shared by all TX compl qs */ + static int be_tx_queues_create(struct be_adapter *adapter) + { + struct be_queue_info *eq, *q, *cq; ++ struct be_tx_obj *txo; ++ u8 i, tc_id; + + adapter->tx_eq.max_eqd = 0; + adapter->tx_eq.min_eqd = 0; + adapter->tx_eq.cur_eqd = 96; + adapter->tx_eq.enable_aic = false; +- /* Alloc Tx Event queue */ ++ + eq = &adapter->tx_eq.q; +- if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, sizeof(struct be_eq_entry))) ++ if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, ++ sizeof(struct be_eq_entry))) + return -1; + +- /* Ask BE to create Tx Event queue */ + if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) +- goto tx_eq_free; +- /* Alloc TX eth compl queue */ +- cq = &adapter->tx_obj.cq; +- if (be_queue_alloc(adapter, cq, TX_CQ_LEN, ++ goto err; ++ adapter->tx_eq.eq_idx = adapter->eq_next_idx++; ++ ++ for_all_tx_queues(adapter, txo, i) { ++ cq = &txo->cq; ++ if (be_queue_alloc(adapter, cq, TX_CQ_LEN, + sizeof(struct be_eth_tx_compl))) +- goto tx_eq_destroy; ++ goto err; + +- /* Ask BE to create Tx eth compl queue */ +- if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) +- goto tx_cq_free; ++ if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) ++ goto err; + +- /* Alloc TX eth queue */ +- q = &adapter->tx_obj.q; +- if (be_queue_alloc(adapter, q, TX_Q_LEN, sizeof(struct be_eth_wrb))) +- goto tx_cq_destroy; ++ q = &txo->q; ++ if (be_queue_alloc(adapter, q, TX_Q_LEN, ++ sizeof(struct be_eth_wrb))) ++ goto err; + +- /* Ask BE to create Tx eth queue */ +- if (be_cmd_txq_create(adapter, q, cq)) +- goto tx_q_free; ++ if (be_cmd_txq_create(adapter, q, cq, &tc_id)) ++ goto err; ++ ++ if (adapter->flags & BE_FLAGS_DCBX) ++ adapter->tc_txq_map[tc_id] = i; ++ } + return 0; + +-tx_q_free: +- be_queue_free(adapter, q); +-tx_cq_destroy: +- be_cmd_q_destroy(adapter, cq, QTYPE_CQ); +-tx_cq_free: +- be_queue_free(adapter, cq); +-tx_eq_destroy: +- be_cmd_q_destroy(adapter, eq, QTYPE_EQ); +-tx_eq_free: +- be_queue_free(adapter, eq); ++err: ++ be_tx_queues_destroy(adapter); + return -1; + } + + static void be_rx_queues_destroy(struct be_adapter *adapter) + { + struct be_queue_info *q; ++ struct be_rx_obj *rxo; ++ int i; + +- q = &adapter->rx_obj.q; +- if (q->created) { +- be_cmd_q_destroy(adapter, q, QTYPE_RXQ); +- be_rx_q_clean(adapter); +- } +- be_queue_free(adapter, q); ++ for_all_rx_queues(adapter, rxo, i) { ++ be_queue_free(adapter, &rxo->q); ++ ++ q = &rxo->cq; ++ if (q->created) ++ be_cmd_q_destroy(adapter, q, QTYPE_CQ); ++ be_queue_free(adapter, q); + +- q = &adapter->rx_obj.cq; +- if (q->created) +- be_cmd_q_destroy(adapter, q, QTYPE_CQ); +- be_queue_free(adapter, q); ++ q = &rxo->rx_eq.q; ++ if (q->created) ++ be_cmd_q_destroy(adapter, q, QTYPE_EQ); ++ be_queue_free(adapter, q); + +- /* Clear any residual events */ +- be_eq_clean(adapter, &adapter->rx_eq); ++ kfree(rxo->page_info_tbl); ++ } ++} + +- q = &adapter->rx_eq.q; +- if (q->created) +- be_cmd_q_destroy(adapter, q, QTYPE_EQ); +- be_queue_free(adapter, q); ++/* Is BE in a multi-channel mode */ ++static inline bool be_is_mc(struct be_adapter *adapter) { ++ return (adapter->function_mode & FLEX10_MODE || ++ adapter->function_mode & VNIC_MODE || ++ adapter->function_mode & UMC_ENABLED); ++} ++ ++static u32 be_num_rxqs_want(struct be_adapter *adapter) ++{ ++ if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && ++ adapter->num_vfs == 0 && be_physfn(adapter) && ++ !be_is_mc(adapter)) { ++ return 1 + MAX_RSS_QS; /* one default non-RSS queue */ ++ } else { ++ dev_warn(&adapter->pdev->dev, ++ "No support for multiple RX queues\n"); ++ return 1; ++ } + } + + static int be_rx_queues_create(struct be_adapter *adapter) + { + struct be_queue_info *eq, *q, *cq; +- int rc; ++ struct be_rx_obj *rxo; ++ int rc, i; + ++ adapter->num_rx_qs = min(be_num_rxqs_want(adapter), ++ msix_enabled(adapter) ? ++ adapter->num_msix_vec - 1 : 1); ++ if (adapter->num_rx_qs != MAX_RX_QS) ++ dev_warn(&adapter->pdev->dev, ++ "Could create only %d receive queues", ++ adapter->num_rx_qs); ++ ++ adapter->max_rx_coal = gro ? BE_INIT_FRAGS_PER_FRAME : 1; + adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; +- adapter->rx_eq.max_eqd = BE_MAX_EQD; +- adapter->rx_eq.min_eqd = 0; +- adapter->rx_eq.cur_eqd = 0; +- adapter->rx_eq.enable_aic = true; ++ for_all_rx_queues(adapter, rxo, i) { ++ rxo->adapter = adapter; ++ rxo->rx_eq.max_eqd = BE_MAX_EQD; ++ rxo->rx_eq.enable_aic = true; + +- /* Alloc Rx Event queue */ +- eq = &adapter->rx_eq.q; +- rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, +- sizeof(struct be_eq_entry)); +- if (rc) +- return rc; ++ /* EQ */ ++ eq = &rxo->rx_eq.q; ++ rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, ++ sizeof(struct be_eq_entry)); ++ if (rc) ++ goto err; + +- /* Ask BE to create Rx Event queue */ +- rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd); +- if (rc) +- goto rx_eq_free; ++ rc = be_cmd_eq_create(adapter, eq, rxo->rx_eq.cur_eqd); ++ if (rc) ++ goto err; + +- /* Alloc RX eth compl queue */ +- cq = &adapter->rx_obj.cq; +- rc = be_queue_alloc(adapter, cq, RX_CQ_LEN, +- sizeof(struct be_eth_rx_compl)); +- if (rc) +- goto rx_eq_destroy; ++ rxo->rx_eq.eq_idx = adapter->eq_next_idx++; + +- /* Ask BE to create Rx eth compl queue */ +- rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); +- if (rc) +- goto rx_cq_free; ++ /* CQ */ ++ cq = &rxo->cq; ++ rc = be_queue_alloc(adapter, cq, RX_CQ_LEN, ++ sizeof(struct be_eth_rx_compl)); ++ if (rc) ++ goto err; + +- /* Alloc RX eth queue */ +- q = &adapter->rx_obj.q; +- rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d)); +- if (rc) +- goto rx_cq_destroy; ++ rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); ++ if (rc) ++ goto err; + +- /* Ask BE to create Rx eth queue */ +- rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, +- BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false); +- if (rc) +- goto rx_q_free; ++ /* Rx Q - will be created in be_open() */ ++ q = &rxo->q; ++ rc = be_queue_alloc(adapter, q, RX_Q_LEN, ++ sizeof(struct be_eth_rx_d)); ++ if (rc) ++ goto err; ++ ++ rxo->page_info_tbl = kzalloc(sizeof(struct be_rx_page_info) * ++ RX_Q_LEN, GFP_KERNEL); ++ if (!rxo->page_info_tbl) ++ goto err; ++ } + + return 0; +-rx_q_free: +- be_queue_free(adapter, q); +-rx_cq_destroy: +- be_cmd_q_destroy(adapter, cq, QTYPE_CQ); +-rx_cq_free: +- be_queue_free(adapter, cq); +-rx_eq_destroy: +- be_cmd_q_destroy(adapter, eq, QTYPE_EQ); +-rx_eq_free: +- be_queue_free(adapter, eq); +- return rc; ++err: ++ be_rx_queues_destroy(adapter); ++ return -1; + } + +-/* There are 8 evt ids per func. Retruns the evt id's bit number */ +-static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id) ++static bool event_peek(struct be_eq_obj *eq_obj) + { +- return eq_id - 8 * be_pci_func(adapter); ++ struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q); ++ if (!eqe->evt) ++ return false; ++ else ++ return true; + } + + static irqreturn_t be_intx(int irq, void *dev) + { + struct be_adapter *adapter = dev; +- int isr; ++ struct be_rx_obj *rxo; ++ int isr, i, tx = 0 , rx = 0; + +- isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + +- be_pci_func(adapter) * CEV_ISR_SIZE); +- if (!isr) +- return IRQ_NONE; ++ if (lancer_chip(adapter)) { ++ if (event_peek(&adapter->tx_eq)) ++ tx = event_handle(adapter, &adapter->tx_eq, false); ++ for_all_rx_queues(adapter, rxo, i) { ++ if (event_peek(&rxo->rx_eq)) ++ rx |= event_handle(adapter, &rxo->rx_eq, true); ++ } + +- event_handle(adapter, &adapter->tx_eq); +- event_handle(adapter, &adapter->rx_eq); ++ if (!(tx || rx)) ++ return IRQ_NONE; ++ } else { ++ isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + ++ (adapter->tx_eq.q.id / 8) * CEV_ISR_SIZE); ++ if (!isr) ++ return IRQ_NONE; ++ ++ if ((1 << adapter->tx_eq.eq_idx & isr)) ++ event_handle(adapter, &adapter->tx_eq, false); ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ if ((1 << rxo->rx_eq.eq_idx & isr)) ++ event_handle(adapter, &rxo->rx_eq, true); ++ } ++ } + + return IRQ_HANDLED; + } + + static irqreturn_t be_msix_rx(int irq, void *dev) + { +- struct be_adapter *adapter = dev; ++ struct be_rx_obj *rxo = dev; ++ struct be_adapter *adapter = rxo->adapter; + +- event_handle(adapter, &adapter->rx_eq); ++ event_handle(adapter, &rxo->rx_eq, true); + + return IRQ_HANDLED; + } +@@ -1353,48 +2046,72 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) + { + struct be_adapter *adapter = dev; + +- event_handle(adapter, &adapter->tx_eq); ++ event_handle(adapter, &adapter->tx_eq, false); + + return IRQ_HANDLED; + } + + static inline bool do_gro(struct be_adapter *adapter, +- struct be_eth_rx_compl *rxcp) ++ struct be_rx_compl_info *rxcp) + { +- int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp); +- int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp); +- +- if (err) +- drvr_stats(adapter)->be_rxcp_err++; +- +- return (tcp_frame && !err) ? true : false; ++ return (!rxcp->tcpf || rxcp->err || adapter->max_rx_coal <= 1 || ++ (rxcp->vlanf && !vlan_configured(adapter))) ? ++ false : true; + } + + int be_poll_rx(struct napi_struct *napi, int budget) + { + struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi); +- struct be_adapter *adapter = +- container_of(rx_eq, struct be_adapter, rx_eq); +- struct be_queue_info *rx_cq = &adapter->rx_obj.cq; +- struct be_eth_rx_compl *rxcp; ++ struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq); ++ struct be_adapter *adapter = rxo->adapter; ++ struct be_queue_info *rx_cq = &rxo->cq; ++ struct be_rx_compl_info *rxcp; + u32 work_done; ++ bool flush_lro = false; + ++ rxo->stats.rx_polls++; + for (work_done = 0; work_done < budget; work_done++) { +- rxcp = be_rx_compl_get(adapter); ++ rxcp = be_rx_compl_get(rxo); + if (!rxcp) + break; + +- if (do_gro(adapter, rxcp)) +- be_rx_compl_process_gro(adapter, rxcp); +- else +- be_rx_compl_process(adapter, rxcp); ++ /* Is it a flush compl that has no data */ ++ if (unlikely(rxcp->num_rcvd == 0)) ++ continue; + +- be_rx_compl_reset(rxcp); ++ if (unlikely(rxcp->port != adapter->port_num)) { ++ be_rx_compl_discard(adapter, rxo, rxcp); ++ be_rx_stats_update(rxo, rxcp); ++ continue; ++ } ++ ++ if (likely((lancer_A0_chip(adapter) && !rxcp->err) || ++ !lancer_A0_chip(adapter))) { ++ if (do_gro(adapter, rxcp)) { ++ if (adapter->gro_supported) { ++ be_rx_compl_process_gro(adapter, rxo, ++ rxcp); ++ } else { ++ be_rx_compl_process_lro(adapter, rxo, ++ rxcp); ++ flush_lro = true; ++ } ++ } else { ++ be_rx_compl_process(adapter, rxo, rxcp); ++ } ++ } else if (lancer_A0_chip(adapter) && rxcp->err) { ++ be_rx_compl_discard(adapter, rxo, rxcp); ++ } ++ ++ be_rx_stats_update(rxo, rxcp); + } + ++ if (flush_lro) ++ lro_flush_all(&rxo->lro_mgr); ++ + /* Refill the queue */ +- if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM) +- be_post_rx_frags(adapter); ++ if (work_done && atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM) ++ be_post_rx_frags(rxo); + + /* All consumed */ + if (work_done < budget) { +@@ -1404,40 +2121,13 @@ int be_poll_rx(struct napi_struct *napi, int budget) + /* More to be consumed; continue with interrupts disabled */ + be_cq_notify(adapter, rx_cq->id, false, work_done); + } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) ++ adapter->netdev->last_rx = jiffies; ++#endif + return work_done; + } + +-void be_process_tx(struct be_adapter *adapter) +-{ +- struct be_queue_info *txq = &adapter->tx_obj.q; +- struct be_queue_info *tx_cq = &adapter->tx_obj.cq; +- struct be_eth_tx_compl *txcp; +- u32 num_cmpl = 0; +- u16 end_idx; +- +- while ((txcp = be_tx_compl_get(tx_cq))) { +- end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, +- wrb_index, txcp); +- be_tx_compl_process(adapter, end_idx); +- num_cmpl++; +- } +- +- if (num_cmpl) { +- be_cq_notify(adapter, tx_cq->id, true, num_cmpl); +- +- /* As Tx wrbs have been freed up, wake up netdev queue if +- * it was stopped due to lack of tx wrbs. +- */ +- if (netif_queue_stopped(adapter->netdev) && +- atomic_read(&txq->used) < txq->len / 2) { +- netif_wake_queue(adapter->netdev); +- } +- +- drvr_stats(adapter)->be_tx_events++; +- drvr_stats(adapter)->be_tx_compl += num_cmpl; +- } +-} +- + /* As TX and MCC share the same EQ check for both TX and MCC completions. + * For TX/MCC we don't honour budget; consume everything + */ +@@ -1446,96 +2136,264 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) + struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); + struct be_adapter *adapter = + container_of(tx_eq, struct be_adapter, tx_eq); ++ struct be_tx_obj *txo; ++ struct be_eth_tx_compl *txcp; ++ int tx_compl, mcc_compl, status = 0; ++ u8 i; ++ u16 num_wrbs; ++ ++ for_all_tx_queues(adapter, txo, i) { ++ tx_compl = 0; ++ num_wrbs = 0; ++ while ((txcp = be_tx_compl_get(&txo->cq))) { ++ num_wrbs += be_tx_compl_process(adapter, txo, ++ AMAP_GET_BITS(struct amap_eth_tx_compl, ++ wrb_index, txcp)); ++ tx_compl++; ++ } ++ if (tx_compl) { ++ be_cq_notify(adapter, txo->cq.id, true, tx_compl); ++ ++ atomic_sub(num_wrbs, &txo->q.used); ++ ++ /* As Tx wrbs have been freed up, wake up netdev queue ++ * if it was stopped due to lack of tx wrbs. */ ++ if (__netif_subqueue_stopped(adapter->netdev, i) && ++ atomic_read(&txo->q.used) < txo->q.len / 2) { ++ netif_wake_subqueue(adapter->netdev, i); ++ } ++ ++ adapter->drv_stats.be_tx_events++; ++ txo->stats.be_tx_compl += tx_compl; ++ } ++ } ++ ++ mcc_compl = be_process_mcc(adapter, &status); ++ ++ if (mcc_compl) { ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; ++ be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl); ++ } + + napi_complete(napi); + +- be_process_tx(adapter); +- +- be_process_mcc(adapter); +- ++ be_eq_notify(adapter, tx_eq->q.id, true, false, 0); + return 1; + } + ++void be_detect_dump_ue(struct be_adapter *adapter) ++{ ++ u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask; ++ u32 i; ++ ++ pci_read_config_dword(adapter->pdev, ++ PCICFG_UE_STATUS_LOW, &ue_status_lo); ++ pci_read_config_dword(adapter->pdev, ++ PCICFG_UE_STATUS_HIGH, &ue_status_hi); ++ pci_read_config_dword(adapter->pdev, ++ PCICFG_UE_STATUS_LOW_MASK, &ue_status_lo_mask); ++ pci_read_config_dword(adapter->pdev, ++ PCICFG_UE_STATUS_HI_MASK, &ue_status_hi_mask); ++ ++ ue_status_lo = (ue_status_lo & (~ue_status_lo_mask)); ++ ue_status_hi = (ue_status_hi & (~ue_status_hi_mask)); ++ ++ if (ue_status_lo || ue_status_hi) { ++ adapter->ue_detected = true; ++ adapter->eeh_err = true; ++ dev_err(&adapter->pdev->dev, "UE Detected!!\n"); ++ } ++ ++ if (ue_status_lo) { ++ for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) { ++ if (ue_status_lo & 1) ++ dev_err(&adapter->pdev->dev, ++ "UE: %s bit set\n", ue_status_low_desc[i]); ++ } ++ } ++ if (ue_status_hi) { ++ for (i = 0; ue_status_hi; ue_status_hi >>= 1, i++) { ++ if (ue_status_hi & 1) ++ dev_err(&adapter->pdev->dev, ++ "UE: %s bit set\n", ue_status_hi_desc[i]); ++ } ++ } ++ ++} ++ + static void be_worker(struct work_struct *work) + { + struct be_adapter *adapter = + container_of(work, struct be_adapter, work.work); ++ struct be_rx_obj *rxo; ++ struct be_tx_obj *txo; ++ int i; + +- be_cmd_get_stats(adapter, &adapter->stats.cmd); ++ if (!adapter->ue_detected && !lancer_chip(adapter)) ++ be_detect_dump_ue(adapter); + +- /* Set EQ delay */ +- be_rx_eqd_update(adapter); ++ /* when interrupts are not yet enabled, just reap any pending ++ * mcc completions */ ++ if (!netif_running(adapter->netdev)) { ++ int mcc_compl, status = 0; + +- be_tx_rate_update(adapter); +- be_rx_rate_update(adapter); ++ mcc_compl = be_process_mcc(adapter, &status); + +- if (adapter->rx_post_starved) { +- adapter->rx_post_starved = false; +- be_post_rx_frags(adapter); ++ if (mcc_compl) { ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; ++ be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); ++ } ++ ++ goto reschedule; ++ } ++ ++ if (!adapter->stats_cmd_sent) ++ be_cmd_get_stats(adapter, &adapter->stats_cmd); ++ ++ for_all_tx_queues(adapter, txo, i) ++ be_tx_rate_update(txo); ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ be_rx_rate_update(rxo); ++ be_rx_eqd_update(adapter, rxo); ++ ++ if (rxo->rx_post_starved) { ++ rxo->rx_post_starved = false; ++ be_post_rx_frags(rxo); ++ } + } + ++reschedule: ++ adapter->work_counter++; + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); + } + ++static void be_msix_disable(struct be_adapter *adapter) ++{ ++ if (msix_enabled(adapter)) { ++ pci_disable_msix(adapter->pdev); ++ adapter->num_msix_vec = 0; ++ } ++} ++ + static void be_msix_enable(struct be_adapter *adapter) + { +- int i, status; ++#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ ++ int i, status, num_vec; + +- for (i = 0; i < BE_NUM_MSIX_VECTORS; i++) ++ num_vec = be_num_rxqs_want(adapter) + 1; ++ ++ for (i = 0; i < num_vec; i++) + adapter->msix_entries[i].entry = i; + +- status = pci_enable_msix(adapter->pdev, adapter->msix_entries, +- BE_NUM_MSIX_VECTORS); +- if (status == 0) +- adapter->msix_enabled = true; ++ status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); ++ if (status == 0) { ++ goto done; ++ } else if (status >= BE_MIN_MSIX_VECTORS) { ++ num_vec = status; ++ if (pci_enable_msix(adapter->pdev, adapter->msix_entries, ++ num_vec) == 0) ++ goto done; ++ } + return; ++done: ++ adapter->num_msix_vec = num_vec; ++ return; ++} ++ ++static void be_sriov_enable(struct be_adapter *adapter) ++{ ++ be_check_sriov_fn_type(adapter); ++#ifdef CONFIG_PCI_IOV ++ if (be_physfn(adapter) && num_vfs) { ++ int status, pos; ++ u16 nvfs; ++ ++ pos = pci_find_ext_capability(adapter->pdev, ++ PCI_EXT_CAP_ID_SRIOV); ++ pci_read_config_word(adapter->pdev, ++ pos + PCI_SRIOV_TOTAL_VF, &nvfs); ++ adapter->num_vfs = num_vfs; ++ if (num_vfs > nvfs) { ++ dev_info(&adapter->pdev->dev, ++ "Device supports %d VFs and not %d\n", ++ nvfs, num_vfs); ++ adapter->num_vfs = nvfs; ++ } ++ ++ status = pci_enable_sriov(adapter->pdev, adapter->num_vfs); ++ if (status) ++ adapter->num_vfs = 0; ++ } ++#endif ++} ++ ++static void be_sriov_disable(struct be_adapter *adapter) ++{ ++#ifdef CONFIG_PCI_IOV ++ if (adapter->num_vfs > 0) { ++ pci_disable_sriov(adapter->pdev); ++ adapter->num_vfs = 0; ++ } ++#endif + } + +-static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) ++static inline int be_msix_vec_get(struct be_adapter *adapter, ++ struct be_eq_obj *eq_obj) + { +- return adapter->msix_entries[ +- be_evt_bit_get(adapter, eq_id)].vector; ++ return adapter->msix_entries[eq_obj->eq_idx].vector; + } + + static int be_request_irq(struct be_adapter *adapter, + struct be_eq_obj *eq_obj, +- void *handler, char *desc) ++ void *handler, char *desc, void *context) + { + struct net_device *netdev = adapter->netdev; + int vec; + + sprintf(eq_obj->desc, "%s-%s", netdev->name, desc); +- vec = be_msix_vec_get(adapter, eq_obj->q.id); +- return request_irq(vec, handler, 0, eq_obj->desc, adapter); ++ vec = be_msix_vec_get(adapter, eq_obj); ++ return request_irq(vec, handler, 0, eq_obj->desc, context); + } + +-static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj) ++static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj, ++ void *context) + { +- int vec = be_msix_vec_get(adapter, eq_obj->q.id); +- free_irq(vec, adapter); ++ int vec = be_msix_vec_get(adapter, eq_obj); ++ free_irq(vec, context); + } + + static int be_msix_register(struct be_adapter *adapter) + { +- int status; ++ struct be_rx_obj *rxo; ++ int status, i; ++ char qname[10]; + +- status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx"); ++ status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx", ++ adapter); + if (status) + goto err; + +- status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx"); +- if (status) +- goto free_tx_irq; ++ for_all_rx_queues(adapter, rxo, i) { ++ sprintf(qname, "rxq%d", i); ++ status = be_request_irq(adapter, &rxo->rx_eq, be_msix_rx, ++ qname, rxo); ++ if (status) ++ goto err_msix; ++ } + + return 0; + +-free_tx_irq: +- be_free_irq(adapter, &adapter->tx_eq); ++err_msix: ++ be_free_irq(adapter, &adapter->tx_eq, adapter); ++ ++ for (i--, rxo = &adapter->rx_obj[i]; i >= 0; i--, rxo--) ++ be_free_irq(adapter, &rxo->rx_eq, rxo); ++ + err: + dev_warn(&adapter->pdev->dev, + "MSIX Request IRQ failed - err %d\n", status); +- pci_disable_msix(adapter->pdev); +- adapter->msix_enabled = false; ++ be_msix_disable(adapter); + return status; + } + +@@ -1544,10 +2402,13 @@ static int be_irq_register(struct be_adapter *adapter) + struct net_device *netdev = adapter->netdev; + int status; + +- if (adapter->msix_enabled) { ++ if (msix_enabled(adapter)) { + status = be_msix_register(adapter); + if (status == 0) + goto done; ++ /* INTx is not supported for VF */ ++ if (!be_physfn(adapter)) ++ return status; + } + + /* INTx */ +@@ -1567,87 +2428,363 @@ done: + static void be_irq_unregister(struct be_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; ++ struct be_rx_obj *rxo; ++ int i; + + if (!adapter->isr_registered) + return; + + /* INTx */ +- if (!adapter->msix_enabled) { ++ if (!msix_enabled(adapter)) { + free_irq(netdev->irq, adapter); + goto done; + } + + /* MSIx */ +- be_free_irq(adapter, &adapter->tx_eq); +- be_free_irq(adapter, &adapter->rx_eq); ++ be_free_irq(adapter, &adapter->tx_eq, adapter); ++ ++ for_all_rx_queues(adapter, rxo, i) ++ be_free_irq(adapter, &rxo->rx_eq, rxo); ++ + done: + adapter->isr_registered = false; +- return; + } + +-static int be_open(struct net_device *netdev) ++static u16 be_select_queue(struct net_device *netdev, ++ struct sk_buff *skb) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *rx_eq = &adapter->rx_eq; ++ u8 prio; ++ ++ if (adapter->num_tx_qs == 1) ++ return 0; ++ ++ prio = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; ++ return adapter->tc_txq_map[adapter->prio_tc_map[prio]]; ++} ++ ++static void be_rx_queues_clear(struct be_adapter *adapter) ++{ ++ struct be_queue_info *q; ++ struct be_rx_obj *rxo; ++ int i; ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ q = &rxo->q; ++ if (q->created) { ++ be_cmd_rxq_destroy(adapter, q); ++ /* After the rxq is invalidated, wait for a grace time ++ * of 1ms for all dma to end and the flush compl to ++ * arrive ++ */ ++ mdelay(1); ++ be_rx_q_clean(adapter, rxo); ++ } ++ ++ /* Clear any residual events */ ++ q = &rxo->rx_eq.q; ++ if (q->created) ++ be_eq_clean(adapter, &rxo->rx_eq); ++ } ++} ++ ++static int be_close(struct net_device *netdev) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_rx_obj *rxo; ++ struct be_tx_obj *txo; + struct be_eq_obj *tx_eq = &adapter->tx_eq; +- bool link_up; +- int status; ++ int vec, i; ++ ++ be_async_mcc_disable(adapter); ++ ++ netif_stop_queue(netdev); ++ netif_carrier_off(netdev); ++ adapter->link_status = LINK_DOWN; ++ ++ if (!lancer_chip(adapter)) ++ be_intr_set(adapter, false); ++ ++ for_all_rx_queues(adapter, rxo, i) ++ napi_disable(&rxo->rx_eq.napi); ++ ++ napi_disable(&tx_eq->napi); ++ ++ if (lancer_chip(adapter)) { ++ be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0); ++ for_all_rx_queues(adapter, rxo, i) ++ be_cq_notify(adapter, rxo->cq.id, false, 0); ++ for_all_tx_queues(adapter, txo, i) ++ be_cq_notify(adapter, txo->cq.id, false, 0); ++ } ++ ++ if (msix_enabled(adapter)) { ++ vec = be_msix_vec_get(adapter, tx_eq); ++ synchronize_irq(vec); ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ vec = be_msix_vec_get(adapter, &rxo->rx_eq); ++ synchronize_irq(vec); ++ } ++ } else { ++ synchronize_irq(netdev->irq); ++ } ++ be_irq_unregister(adapter); ++ ++ /* Wait for all pending tx completions to arrive so that ++ * all tx skbs are freed. ++ */ ++ for_all_tx_queues(adapter, txo, i) ++ be_tx_compl_clean(adapter, txo); ++ ++ be_rx_queues_clear(adapter); ++ return 0; ++} ++ ++static int be_rx_queues_setup(struct be_adapter *adapter) ++{ ++ struct be_rx_obj *rxo; ++ int rc, i; ++ u8 rsstable[MAX_RSS_QS]; ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, ++ rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE, ++ adapter->if_handle, ++ (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id); ++ if (rc) ++ return rc; ++ } ++ ++ if (be_multi_rxq(adapter)) { ++ for_all_rss_queues(adapter, rxo, i) ++ rsstable[i] = rxo->rss_id; ++ ++ rc = be_cmd_rss_config(adapter, rsstable, ++ adapter->num_rx_qs - 1); ++ if (rc) ++ return rc; ++ } + + /* First time posting */ +- be_post_rx_frags(adapter); ++ for_all_rx_queues(adapter, rxo, i) { ++ be_post_rx_frags(rxo); ++ napi_enable(&rxo->rx_eq.napi); ++ } ++ return 0; ++} ++ ++static int be_open(struct net_device *netdev) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_eq_obj *tx_eq = &adapter->tx_eq; ++ struct be_rx_obj *rxo; ++ int link_status; ++ int status, i; ++ u8 mac_speed; ++ u16 link_speed; ++ ++ status = be_rx_queues_setup(adapter); ++ if (status) ++ goto err; + +- napi_enable(&rx_eq->napi); + napi_enable(&tx_eq->napi); + + be_irq_register(adapter); + +- be_intr_set(adapter, true); ++ if (!lancer_chip(adapter)) ++ be_intr_set(adapter, true); + + /* The evt queues are created in unarmed state; arm them */ +- be_eq_notify(adapter, rx_eq->q.id, true, false, 0); ++ for_all_rx_queues(adapter, rxo, i) { ++ be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0); ++ be_cq_notify(adapter, rxo->cq.id, true, 0); ++ } + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); + +- /* Rx compl queue may be in unarmed state; rearm it */ +- be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0); ++ /* Now that interrupts are on we can process async mcc */ ++ be_async_mcc_enable(adapter); + +- status = be_cmd_link_status_query(adapter, &link_up); ++ status = be_cmd_link_status_query(adapter, &link_status, &mac_speed, ++ &link_speed, 0); + if (status) +- goto ret_sts; +- be_link_status_update(adapter, link_up); ++ goto err; ++ be_link_status_update(adapter, link_status); + +- status = be_vid_config(adapter); ++ status = be_vid_config(adapter, false, 0); + if (status) +- goto ret_sts; ++ goto err; + +- status = be_cmd_set_flow_control(adapter, +- adapter->tx_fc, adapter->rx_fc); +- if (status) +- goto ret_sts; ++ if (be_physfn(adapter)) { ++ status = be_cmd_set_flow_control(adapter, ++ adapter->tx_fc, adapter->rx_fc); ++ if (status) ++ goto err; ++ } ++ ++ return 0; ++err: ++ be_close(adapter->netdev); ++ return -EIO; ++} ++ ++static int be_setup_wol(struct be_adapter *adapter, bool enable) ++{ ++ struct be_dma_mem cmd; ++ int status = 0; ++ u8 mac[ETH_ALEN]; ++ ++ memset(mac, 0, ETH_ALEN); ++ ++ cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); ++ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma); ++ if (cmd.va == NULL) ++ return -1; ++ memset(cmd.va, 0, cmd.size); ++ ++ if (enable) { ++ status = pci_write_config_dword(adapter->pdev, ++ PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK); ++ if (status) { ++ dev_err(&adapter->pdev->dev, ++ "Could not enable Wake-on-lan\n"); ++ pci_free_consistent(adapter->pdev, cmd.size, cmd.va, ++ cmd.dma); ++ return status; ++ } ++ status = be_cmd_enable_magic_wol(adapter, ++ adapter->netdev->dev_addr, &cmd); ++ pci_enable_wake(adapter->pdev, PCI_D3hot, 1); ++ pci_enable_wake(adapter->pdev, PCI_D3cold, 1); ++ } else { ++ status = be_cmd_enable_magic_wol(adapter, mac, &cmd); ++ pci_enable_wake(adapter->pdev, PCI_D3hot, 0); ++ pci_enable_wake(adapter->pdev, PCI_D3cold, 0); ++ } ++ ++ pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); ++ return status; ++} ++ ++/* ++ * Generate a seed MAC address from the PF MAC Address using jhash. ++ * MAC Address for VFs are assigned incrementally starting from the seed. ++ * These addresses are programmed in the ASIC by the PF and the VF driver ++ * queries for the MAC address during its probe. ++ */ ++static inline int be_vf_eth_addr_config(struct be_adapter *adapter) ++{ ++ u32 vf = 0; ++ int status = 0; ++ u8 mac[ETH_ALEN]; ++ ++ be_vf_eth_addr_generate(adapter, mac); ++ ++ for (vf = 0; vf < adapter->num_vfs; vf++) { ++ status = be_cmd_pmac_add(adapter, mac, ++ adapter->vf_cfg[vf].vf_if_handle, ++ &adapter->vf_cfg[vf].vf_pmac_id, ++ vf + 1); ++ if (status) ++ dev_err(&adapter->pdev->dev, ++ "Mac address add failed for VF %d\n", vf); ++ else ++ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); + +- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); +-ret_sts: ++ mac[5] += 1; ++ } + return status; + } + ++static inline void be_vf_eth_addr_rem(struct be_adapter *adapter) ++{ ++ u32 vf; ++ ++ for (vf = 0; vf < adapter->num_vfs; vf++) { ++ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) ++ be_cmd_pmac_del(adapter, ++ adapter->vf_cfg[vf].vf_if_handle, ++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ } ++} ++ ++static int be_num_txqs_want(struct be_adapter *adapter) ++{ ++ if (adapter->num_vfs > 0 || be_is_mc(adapter) || ++ lancer_chip(adapter) || !be_physfn(adapter) || ++ adapter->generation == BE_GEN2) ++ return 1; ++ else ++ return MAX_TX_QS; ++} ++ + static int be_setup(struct be_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +- u32 cap_flags, en_flags; +- int status; +- +- cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | +- BE_IF_FLAGS_MCAST_PROMISCUOUS | +- BE_IF_FLAGS_PROMISCUOUS | +- BE_IF_FLAGS_PASS_L3L4_ERRORS; +- en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | +- BE_IF_FLAGS_PASS_L3L4_ERRORS; ++ int status, fw_num_txqs, num_txqs; ++ u32 cap_flags, en_flags, vf = 0; ++ u8 mac[ETH_ALEN]; ++ ++ num_txqs = be_num_txqs_want(adapter); ++ if (num_txqs > 1) { ++ be_cmd_req_pg_pfc(adapter, &fw_num_txqs); ++ num_txqs = min(num_txqs, fw_num_txqs); ++ } ++ adapter->num_tx_qs = num_txqs; ++ if (adapter->num_tx_qs != MAX_TX_QS) ++ netif_set_real_num_tx_queues(adapter->netdev, ++ adapter->num_tx_qs); ++ ++ be_cmd_req_native_mode(adapter); ++ ++ cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | ++ BE_IF_FLAGS_BROADCAST | ++ BE_IF_FLAGS_MULTICAST; ++ ++ if (be_physfn(adapter)) { ++ if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { ++ cap_flags |= BE_IF_FLAGS_RSS; ++ en_flags |= BE_IF_FLAGS_RSS; ++ } ++ cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS | ++ BE_IF_FLAGS_PROMISCUOUS; ++ if (!lancer_A0_chip(adapter)) { ++ cap_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; ++ en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; ++ } ++ } + + status = be_cmd_if_create(adapter, cap_flags, en_flags, + netdev->dev_addr, false/* pmac_invalid */, +- &adapter->if_handle, &adapter->pmac_id); ++ &adapter->if_handle, &adapter->pmac_id, 0); + if (status != 0) + goto do_none; + ++ if (be_physfn(adapter)) { ++ while (vf < adapter->num_vfs) { ++ cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | ++ BE_IF_FLAGS_BROADCAST; ++ status = be_cmd_if_create(adapter, cap_flags, ++ en_flags, mac, true, ++ &adapter->vf_cfg[vf].vf_if_handle, ++ NULL, vf+1); ++ if (status) { ++ dev_err(&adapter->pdev->dev, ++ "Interface Create failed for VF %d\n", vf); ++ goto if_destroy; ++ } ++ adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID; ++ vf++; ++ } ++ } else { ++ status = be_cmd_mac_addr_query(adapter, mac, ++ MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); ++ if (!status) { ++ memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); ++ memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); ++ } ++ } ++ + status = be_tx_queues_create(adapter); + if (status != 0) + goto if_destroy; +@@ -1656,10 +2793,15 @@ static int be_setup(struct be_adapter *adapter) + if (status != 0) + goto tx_qs_destroy; + ++ /* Allow all priorities by default. A GRP5 evt may modify this */ ++ adapter->vlan_prio_bmap = 0xff; ++ + status = be_mcc_queues_create(adapter); + if (status != 0) + goto rx_qs_destroy; + ++ adapter->link_speed = -1; ++ + return 0; + + rx_qs_destroy: +@@ -1667,158 +2809,392 @@ rx_qs_destroy: + tx_qs_destroy: + be_tx_queues_destroy(adapter); + if_destroy: +- be_cmd_if_destroy(adapter, adapter->if_handle); ++ if (be_physfn(adapter)) { ++ for (vf = 0; vf < adapter->num_vfs; vf++) ++ if (adapter->vf_cfg[vf].vf_if_handle) ++ be_cmd_if_destroy(adapter, ++ adapter->vf_cfg[vf].vf_if_handle, ++ vf + 1); ++ } ++ be_cmd_if_destroy(adapter, adapter->if_handle, 0); + do_none: + return status; + } + + static int be_clear(struct be_adapter *adapter) + { ++ int vf; ++ ++ if (be_physfn(adapter) && adapter->num_vfs) ++ be_vf_eth_addr_rem(adapter); ++ + be_mcc_queues_destroy(adapter); + be_rx_queues_destroy(adapter); + be_tx_queues_destroy(adapter); ++ adapter->eq_next_idx = 0; + +- be_cmd_if_destroy(adapter, adapter->if_handle); ++ if (be_physfn(adapter)) { ++ for (vf = 0; vf < adapter->num_vfs; vf++) ++ if (adapter->vf_cfg[vf].vf_if_handle) ++ be_cmd_if_destroy(adapter, ++ adapter->vf_cfg[vf].vf_if_handle, vf + 1); ++ } ++ be_cmd_if_destroy(adapter, adapter->if_handle, 0); + ++ /* tell fw we're done with firing cmds */ ++ be_cmd_fw_clean(adapter); + return 0; + } + +-static int be_close(struct net_device *netdev) ++static void be_cpy_drv_ver(struct be_adapter *adapter, void *va) ++{ ++ struct mgmt_controller_attrib *attrib = ++ (struct mgmt_controller_attrib *) ((u8*) va + ++ sizeof(struct be_cmd_resp_hdr)); ++ ++ memcpy(attrib->hba_attribs.driver_version_string, ++ DRV_VER, sizeof(DRV_VER)); ++ attrib->pci_bus_number = adapter->pdev->bus->number; ++ attrib->pci_device_number = PCI_SLOT(adapter->pdev->devfn); ++ return; ++} ++ ++#define IOCTL_COOKIE "SERVERENGINES CORP" ++static int be_do_ioctl(struct net_device *netdev, ++ struct ifreq *ifr, int cmd) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *rx_eq = &adapter->rx_eq; +- struct be_eq_obj *tx_eq = &adapter->tx_eq; +- int vec; ++ struct be_cmd_req_hdr req; ++ struct be_cmd_resp_hdr *resp; ++ void *data = ifr->ifr_data; ++ void *ioctl_ptr; ++ void *va; ++ dma_addr_t dma; ++ u32 req_size; ++ int status, ret = 0; ++ u8 cookie[32]; ++ ++ switch (cmd) { ++ case SIOCDEVPRIVATE: ++ if (copy_from_user(cookie, data, strlen(IOCTL_COOKIE))) ++ return -EFAULT; ++ ++ if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) ++ return -EINVAL; + +- cancel_delayed_work_sync(&adapter->work); ++ ioctl_ptr = (u8 *)data + strlen(IOCTL_COOKIE); ++ if (copy_from_user(&req, ioctl_ptr, ++ sizeof(struct be_cmd_req_hdr))) ++ return -EFAULT; + +- netif_stop_queue(netdev); +- netif_carrier_off(netdev); +- adapter->link_up = false; ++ req_size = le32_to_cpu(req.request_length); ++ if (req_size > 65536) ++ return -EINVAL; + +- be_intr_set(adapter, false); ++ req_size += sizeof(struct be_cmd_req_hdr); ++ va = pci_alloc_consistent(adapter->pdev, req_size, &dma); ++ if (!va) ++ return -ENOMEM; ++ if (copy_from_user(va, ioctl_ptr, req_size)) { ++ ret = -EFAULT; ++ break; ++ } + +- if (adapter->msix_enabled) { +- vec = be_msix_vec_get(adapter, tx_eq->q.id); +- synchronize_irq(vec); +- vec = be_msix_vec_get(adapter, rx_eq->q.id); +- synchronize_irq(vec); +- } else { +- synchronize_irq(netdev->irq); ++ status = be_cmd_pass_ext_ioctl(adapter, dma, req_size, va); ++ if (status == -1) { ++ ret = -EIO; ++ break; ++ } ++ ++ resp = (struct be_cmd_resp_hdr *) va; ++ if (!status) { ++ if (req.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) ++ be_cpy_drv_ver(adapter, va); ++ } ++ ++ if (copy_to_user(ioctl_ptr, va, req_size)) { ++ ret = -EFAULT; ++ break; ++ } ++ break; ++ default: ++ return -EOPNOTSUPP; + } +- be_irq_unregister(adapter); + +- napi_disable(&rx_eq->napi); +- napi_disable(&tx_eq->napi); ++ if (va) ++ pci_free_consistent(adapter->pdev, req_size, va, dma); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void be_netpoll(struct net_device *netdev) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_rx_obj *rxo; ++ int i; + +- /* Wait for all pending tx completions to arrive so that +- * all tx skbs are freed. +- */ +- be_tx_compl_clean(adapter); ++ event_handle(adapter, &adapter->tx_eq, false); ++ for_all_rx_queues(adapter, rxo, i) ++ event_handle(adapter, &rxo->rx_eq, true); ++ ++ return; ++} ++#endif ++ ++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; ++ ++ 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; + } + +-#define FW_FILE_HDR_SIGN "ServerEngines Corp. " ++static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev) ++{ ++ struct net_lro_mgr *lro_mgr; ++ struct be_rx_obj *rxo; ++ int i; ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ lro_mgr = &rxo->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 = rxo->lro_desc; ++ lro_mgr->get_frag_header = be_get_frag_header; ++ lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME; ++ } ++ ++#ifdef NETIF_F_GRO ++ netdev->features |= NETIF_F_GRO; ++ adapter->gro_supported = true; ++#endif ++} ++ ++#define FW_FILE_HDR_SIGN "ServerEngines Corp. " + char flash_cookie[2][16] = {"*** SE FLAS", + "H DIRECTORY *** "}; +-static int be_flash_image(struct be_adapter *adapter, ++ ++static bool be_flash_redboot(struct be_adapter *adapter, ++ const u8 *p, u32 img_start, int image_size, ++ int hdr_size) ++{ ++ u32 crc_offset; ++ u8 flashed_crc[4]; ++ int status; ++ ++ crc_offset = hdr_size + img_start + image_size - 4; ++ ++ p += crc_offset; ++ ++ status = be_cmd_get_flash_crc(adapter, flashed_crc, ++ (image_size - 4)); ++ if (status) { ++ dev_err(&adapter->pdev->dev, ++ "could not get crc from flash, not flashing redboot\n"); ++ return false; ++ } ++ ++ /*update redboot only if crc does not match*/ ++ if (!memcmp(flashed_crc, p, 4)) ++ return false; ++ else ++ return true; ++} ++ ++static bool phy_flashing_required(struct be_adapter *adapter) ++{ ++ int status = 0; ++ struct be_phy_info phy_info; ++ ++ status = be_cmd_get_phy_info(adapter, &phy_info); ++ if (status) ++ return false; ++ if ((phy_info.phy_type == TN_8022) && ++ (phy_info.interface_type == PHY_TYPE_BASET_10GB)) { ++ return true; ++ } ++ return false; ++} ++ ++static int be_flash_data(struct be_adapter *adapter, + const struct firmware *fw, +- struct be_dma_mem *flash_cmd, u32 flash_type) ++ struct be_dma_mem *flash_cmd, int num_of_images) ++ + { +- int status; +- u32 flash_op, image_offset = 0, total_bytes, image_size = 0; ++ int status = 0, i, filehdr_size = 0; ++ u32 total_bytes = 0, flash_op; + int num_bytes; + const u8 *p = fw->data; + struct be_cmd_write_flashrom *req = flash_cmd->va; ++ struct flash_comp *pflashcomp; ++ int num_comp; + +- switch (flash_type) { +- case FLASHROM_TYPE_ISCSI_ACTIVE: +- image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START; +- image_size = FLASH_IMAGE_MAX_SIZE; +- break; +- case FLASHROM_TYPE_ISCSI_BACKUP: +- image_offset = FLASH_iSCSI_BACKUP_IMAGE_START; +- image_size = FLASH_IMAGE_MAX_SIZE; +- break; +- case FLASHROM_TYPE_FCOE_FW_ACTIVE: +- image_offset = FLASH_FCoE_PRIMARY_IMAGE_START; +- image_size = FLASH_IMAGE_MAX_SIZE; +- break; +- case FLASHROM_TYPE_FCOE_FW_BACKUP: +- image_offset = FLASH_FCoE_BACKUP_IMAGE_START; +- image_size = FLASH_IMAGE_MAX_SIZE; +- break; +- case FLASHROM_TYPE_BIOS: +- image_offset = FLASH_iSCSI_BIOS_START; +- image_size = FLASH_BIOS_IMAGE_MAX_SIZE; +- break; +- case FLASHROM_TYPE_FCOE_BIOS: +- image_offset = FLASH_FCoE_BIOS_START; +- image_size = FLASH_BIOS_IMAGE_MAX_SIZE; +- break; +- case FLASHROM_TYPE_PXE_BIOS: +- image_offset = FLASH_PXE_BIOS_START; +- image_size = FLASH_BIOS_IMAGE_MAX_SIZE; +- break; +- default: +- return 0; ++ struct flash_comp gen3_flash_types[10] = { ++ { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g3}, ++ { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT, ++ FLASH_REDBOOT_IMAGE_MAX_SIZE_g3}, ++ { FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g3}, ++ { FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g3}, ++ { FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g3}, ++ { FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g3}, ++ { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g3}, ++ { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g3}, ++ { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW, ++ FLASH_NCSI_IMAGE_MAX_SIZE_g3}, ++ { FLASH_PHY_FW_START_g3, IMG_TYPE_PHY_FW, ++ FLASH_PHY_FW_IMAGE_MAX_SIZE_g3} ++ }; ++ struct flash_comp gen2_flash_types[8] = { ++ { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g2}, ++ { FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT, ++ FLASH_REDBOOT_IMAGE_MAX_SIZE_g2}, ++ { FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g2}, ++ { FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g2}, ++ { FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g2}, ++ { FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g2}, ++ { FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g2}, ++ { FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g2} ++ }; ++ if (adapter->generation == BE_GEN3) { ++ pflashcomp = gen3_flash_types; ++ filehdr_size = sizeof(struct flash_file_hdr_g3); ++ num_comp = ARRAY_SIZE(gen3_flash_types); ++ } else { ++ pflashcomp = gen2_flash_types; ++ filehdr_size = sizeof(struct flash_file_hdr_g2); ++ num_comp = ARRAY_SIZE(gen2_flash_types); + } ++ for (i = 0; i < num_comp; i++) { ++ if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) && ++ memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) ++ continue; ++ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) { ++ if (!phy_flashing_required(adapter)) ++ continue; ++ } ++ if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) && ++ (!be_flash_redboot(adapter, fw->data, ++ pflashcomp[i].offset, pflashcomp[i].size, filehdr_size + ++ (num_of_images * sizeof(struct image_hdr))))) ++ continue; + +- p += sizeof(struct flash_file_hdr) + image_offset; +- if (p + image_size > fw->data + fw->size) +- return -1; +- +- total_bytes = image_size; +- +- while (total_bytes) { +- if (total_bytes > 32*1024) +- num_bytes = 32*1024; +- else +- num_bytes = total_bytes; +- total_bytes -= num_bytes; +- +- if (!total_bytes) +- flash_op = FLASHROM_OPER_FLASH; +- else +- flash_op = FLASHROM_OPER_SAVE; +- memcpy(req->params.data_buf, p, num_bytes); +- p += num_bytes; +- status = be_cmd_write_flashrom(adapter, flash_cmd, +- flash_type, flash_op, num_bytes); +- if (status) { +- dev_err(&adapter->pdev->dev, +- "cmd to write to flash rom failed. type/op %d/%d\n", +- flash_type, flash_op); ++ p = fw->data; ++ p += filehdr_size + pflashcomp[i].offset ++ + (num_of_images * sizeof(struct image_hdr)); ++ if (p + pflashcomp[i].size > fw->data + fw->size) + return -1; ++ total_bytes = pflashcomp[i].size; ++ while (total_bytes) { ++ if (total_bytes > 32*1024) ++ num_bytes = 32*1024; ++ else ++ num_bytes = total_bytes; ++ total_bytes -= num_bytes; ++ if (!total_bytes) { ++ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) ++ flash_op = FLASHROM_OPER_PHY_FLASH; ++ else ++ flash_op = FLASHROM_OPER_FLASH; ++ } else { ++ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) ++ flash_op = FLASHROM_OPER_PHY_SAVE; ++ else ++ flash_op = FLASHROM_OPER_SAVE; ++ } ++ memcpy(req->params.data_buf, p, num_bytes); ++ p += num_bytes; ++ status = be_cmd_write_flashrom(adapter, flash_cmd, ++ pflashcomp[i].optype, flash_op, num_bytes); ++ if (status) { ++ if ((status == ILLEGAL_IOCTL_REQ) && ++ (pflashcomp[i].optype == ++ IMG_TYPE_PHY_FW)) ++ break; ++ dev_err(&adapter->pdev->dev, ++ "cmd to write to flash rom failed.\n"); ++ return -1; ++ } ++ yield(); + } +- yield(); + } +- + return 0; + } + ++static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr) ++{ ++ if (fhdr == NULL) ++ return 0; ++ if (fhdr->build[0] == '3') ++ return BE_GEN3; ++ else if (fhdr->build[0] == '2') ++ return BE_GEN2; ++ else ++ return 0; ++} ++ + int be_load_fw(struct be_adapter *adapter, u8 *func) + { + char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; + const struct firmware *fw; +- struct flash_file_hdr *fhdr; +- struct flash_section_info *fsec = NULL; ++ struct flash_file_hdr_g2 *fhdr; ++ struct flash_file_hdr_g3 *fhdr3; ++ struct image_hdr *img_hdr_ptr = NULL; + struct be_dma_mem flash_cmd; +- int status; ++ int status, i = 0, num_imgs = 0; + const u8 *p; +- bool entry_found = false; +- int flash_type; +- char fw_ver[FW_VER_LEN]; +- char fw_cfg; + +- status = be_cmd_get_fw_ver(adapter, fw_ver); +- if (status) +- return status; ++ if (!netif_running(adapter->netdev)) { ++ dev_err(&adapter->pdev->dev, ++ "Firmware load not allowed (interface is down)\n"); ++ return -1; ++ } + +- fw_cfg = *(fw_ver + 2); +- if (fw_cfg == '0') +- fw_cfg = '1'; + strcpy(fw_file, func); + + status = request_firmware(&fw, fw_file, &adapter->pdev->dev); +@@ -1826,34 +3202,9 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) + goto fw_exit; + + p = fw->data; +- fhdr = (struct flash_file_hdr *) p; +- if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) { +- dev_err(&adapter->pdev->dev, +- "Firmware(%s) load error (signature did not match)\n", +- fw_file); +- status = -1; +- goto fw_exit; +- } +- ++ fhdr = (struct flash_file_hdr_g2 *) p; + dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + +- p += sizeof(struct flash_file_hdr); +- while (p < (fw->data + fw->size)) { +- fsec = (struct flash_section_info *)p; +- if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) { +- entry_found = true; +- break; +- } +- p += 32; +- } +- +- if (!entry_found) { +- status = -1; +- dev_err(&adapter->pdev->dev, +- "Flash cookie not found in firmware image\n"); +- goto fw_exit; +- } +- + flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; + flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size, + &flash_cmd.dma); +@@ -1864,12 +3215,25 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) + goto fw_exit; + } + +- for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE; +- flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) { +- status = be_flash_image(adapter, fw, &flash_cmd, +- flash_type); +- if (status) +- break; ++ if ((adapter->generation == BE_GEN3) && ++ (get_ufigen_type(fhdr) == BE_GEN3)) { ++ fhdr3 = (struct flash_file_hdr_g3 *) fw->data; ++ num_imgs = le32_to_cpu(fhdr3->num_imgs); ++ for (i = 0; i < num_imgs; i++) { ++ img_hdr_ptr = (struct image_hdr *) (fw->data + ++ (sizeof(struct flash_file_hdr_g3) + ++ i * sizeof(struct image_hdr))); ++ if (le32_to_cpu(img_hdr_ptr->imageid) == 1) ++ status = be_flash_data(adapter, fw, &flash_cmd, ++ num_imgs); ++ } ++ } else if ((adapter->generation == BE_GEN2) && ++ (get_ufigen_type(fhdr) == BE_GEN2)) { ++ status = be_flash_data(adapter, fw, &flash_cmd, 0); ++ } else { ++ dev_err(&adapter->pdev->dev, ++ "UFI and Interface are not compatible for flashing\n"); ++ status = -1; + } + + pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va, +@@ -1879,14 +3243,14 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) + goto fw_exit; + } + +- dev_info(&adapter->pdev->dev, "Firmware flashed succesfully\n"); ++ dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); + + fw_exit: + release_firmware(fw); + return status; + } + +-static struct net_device_ops be_netdev_ops = { ++static net_device_ops_no_const be_netdev_ops = { + .ndo_open = be_open, + .ndo_stop = be_close, + .ndo_start_xmit = be_xmit, +@@ -1898,15 +3262,32 @@ static struct net_device_ops be_netdev_ops = { + .ndo_vlan_rx_register = be_vlan_register, + .ndo_vlan_rx_add_vid = be_vlan_add_vid, + .ndo_vlan_rx_kill_vid = be_vlan_rem_vid, ++#ifdef HAVE_SRIOV_CONFIG ++ .ndo_set_vf_mac = be_set_vf_mac, ++ .ndo_set_vf_vlan = be_set_vf_vlan, ++ .ndo_set_vf_tx_rate = be_set_vf_tx_rate, ++ .ndo_get_vf_config = be_get_vf_config, ++#endif ++ .ndo_do_ioctl = be_do_ioctl, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = be_netpoll, ++#endif + }; + +-static void be_netdev_init(struct net_device *netdev) ++static int be_netdev_init(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_rx_obj *rxo; ++ int i, status = 0; + + netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | +- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM | +- NETIF_F_GRO; ++ NETIF_F_HW_VLAN_TX | NETIF_F_HW_CSUM | NETIF_F_TSO6; ++ ++ netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | ++ NETIF_F_HW_CSUM; ++ ++ netdev->features |= NETIF_F_VLAN_SG | NETIF_F_VLAN_TSO | ++ NETIF_F_VLAN_CSUM; + + netdev->flags |= IFF_MULTICAST; + +@@ -1918,17 +3299,30 @@ static void be_netdev_init(struct net_device *netdev) + + netif_set_gso_max_size(netdev, 65535); + ++ if (adapter->flags & BE_FLAGS_DCBX) ++ be_netdev_ops.ndo_select_queue = be_select_queue; + BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); +- ++ + SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); + +- netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, +- BE_NAPI_WEIGHT); +- netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, ++ be_lro_init(adapter, netdev); ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ status = be_netif_napi_add(netdev, &rxo->rx_eq.napi, be_poll_rx, ++ BE_NAPI_WEIGHT); ++ if (status) { ++ dev_err(&adapter->pdev->dev, "dummy netdev alloc fail" ++ "for rxo:%d\n", i); ++ return status; ++ } ++ } ++ status = be_netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, + BE_NAPI_WEIGHT); ++ if (status) ++ dev_err(&adapter->pdev->dev, "dummy netdev alloc fail" ++ "for tx\n"); + +- netif_carrier_off(netdev); +- netif_stop_queue(netdev); ++ return status; + } + + static void be_unmap_pci_bars(struct be_adapter *adapter) +@@ -1937,37 +3331,62 @@ static void be_unmap_pci_bars(struct be_adapter *adapter) + iounmap(adapter->csr); + if (adapter->db) + iounmap(adapter->db); +- if (adapter->pcicfg) ++ if (adapter->pcicfg && be_physfn(adapter)) + iounmap(adapter->pcicfg); + } + + static int be_map_pci_bars(struct be_adapter *adapter) + { ++ struct pci_dev *pdev = adapter->pdev; + u8 __iomem *addr; +- int pcicfg_reg; ++ int pcicfg_reg, db_reg; + +- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2), +- pci_resource_len(adapter->pdev, 2)); +- if (addr == NULL) +- return -ENOMEM; +- adapter->csr = addr; ++ if (lancer_chip(adapter)) { ++ addr = ioremap_nocache(pci_resource_start(pdev, 0), ++ pci_resource_len(adapter->pdev, 0)); ++ if (addr == NULL) ++ return -ENOMEM; ++ adapter->db = addr; ++ return 0; ++ } + +- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4), +- 128 * 1024); +- if (addr == NULL) +- goto pci_map_err; +- adapter->db = addr; ++ if (be_physfn(adapter)) { ++ addr = ioremap_nocache(pci_resource_start(pdev, 2), ++ pci_resource_len(pdev, 2)); ++ if (addr == NULL) ++ return -ENOMEM; ++ adapter->csr = addr; ++ adapter->netdev->mem_start = pci_resource_start(pdev, 2); ++ adapter->netdev->mem_end = pci_resource_start(pdev, 2) + ++ pci_resource_len(pdev, 2); ++ } + +- if (adapter->generation == BE_GEN2) ++ if (adapter->generation == BE_GEN2) { + pcicfg_reg = 1; +- else ++ db_reg = 4; ++ } else { + pcicfg_reg = 0; ++ if (be_physfn(adapter)) ++ db_reg = 4; ++ else ++ db_reg = 0; ++ } + +- addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg), +- pci_resource_len(adapter->pdev, pcicfg_reg)); ++ addr = ioremap_nocache(pci_resource_start(pdev, db_reg), ++ pci_resource_len(pdev, db_reg)); + if (addr == NULL) + goto pci_map_err; +- adapter->pcicfg = addr; ++ adapter->db = addr; ++ ++ if (be_physfn(adapter)) { ++ addr = ioremap_nocache( ++ pci_resource_start(pdev, pcicfg_reg), ++ pci_resource_len(pdev, pcicfg_reg)); ++ if (addr == NULL) ++ goto pci_map_err; ++ adapter->pcicfg = addr; ++ } else ++ adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET; + + return 0; + pci_map_err: +@@ -1985,40 +3404,69 @@ static void be_ctrl_cleanup(struct be_adapter *adapter) + if (mem->va) + pci_free_consistent(adapter->pdev, mem->size, + mem->va, mem->dma); ++ ++ mem = &adapter->rx_filter; ++ if (mem->va) ++ pci_free_consistent(adapter->pdev, mem->size, ++ mem->va, mem->dma); + } + + static int be_ctrl_init(struct be_adapter *adapter) + { + struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced; + struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem; ++ struct be_dma_mem *rx_filter = &adapter->rx_filter; + int status; + + status = be_map_pci_bars(adapter); + if (status) +- return status; ++ goto done; + + mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; + mbox_mem_alloc->va = pci_alloc_consistent(adapter->pdev, + mbox_mem_alloc->size, &mbox_mem_alloc->dma); + if (!mbox_mem_alloc->va) { +- be_unmap_pci_bars(adapter); +- return -1; ++ status = -ENOMEM; ++ goto unmap_pci_bars; + } ++ + mbox_mem_align->size = sizeof(struct be_mcc_mailbox); + mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); + mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); + memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); +- spin_lock_init(&adapter->mbox_lock); ++ ++ rx_filter->size = sizeof(struct be_cmd_req_rx_filter); ++ rx_filter->va = pci_alloc_consistent(adapter->pdev, rx_filter->size, ++ &rx_filter->dma); ++ if (rx_filter->va == NULL) { ++ status = -ENOMEM; ++ goto free_mbox; ++ } ++ memset(rx_filter->va, 0, rx_filter->size); ++ ++ mutex_init(&adapter->mbox_lock); + spin_lock_init(&adapter->mcc_lock); + spin_lock_init(&adapter->mcc_cq_lock); + ++ init_completion(&adapter->flash_compl); ++ ++ PCI_SAVE_STATE(adapter->pdev); + return 0; ++ ++free_mbox: ++ pci_free_consistent(adapter->pdev, mbox_mem_alloc->size, ++ mbox_mem_alloc->va, mbox_mem_alloc->dma); ++ ++unmap_pci_bars: ++ be_unmap_pci_bars(adapter); ++ ++done: ++ return status; + } + + static void be_stats_cleanup(struct be_adapter *adapter) + { +- struct be_stats_obj *stats = &adapter->stats; +- struct be_dma_mem *cmd = &stats->cmd; ++ struct be_dma_mem *cmd = &adapter->stats_cmd; + + if (cmd->va) + pci_free_consistent(adapter->pdev, cmd->size, +@@ -2027,10 +3475,12 @@ static void be_stats_cleanup(struct be_adapter *adapter) + + static int be_stats_init(struct be_adapter *adapter) + { +- struct be_stats_obj *stats = &adapter->stats; +- struct be_dma_mem *cmd = &stats->cmd; ++ struct be_dma_mem *cmd = &adapter->stats_cmd; + +- cmd->size = sizeof(struct be_cmd_req_get_stats); ++ if (adapter->generation == BE_GEN2) ++ cmd->size = sizeof(struct be_cmd_req_get_stats_v0); ++ else ++ cmd->size = sizeof(struct be_cmd_req_get_stats_v1); + cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); + if (cmd->va == NULL) + return -1; +@@ -2041,9 +3491,17 @@ static int be_stats_init(struct be_adapter *adapter) + static void __devexit be_remove(struct pci_dev *pdev) + { + struct be_adapter *adapter = pci_get_drvdata(pdev); ++ + if (!adapter) + return; + ++ cancel_delayed_work_sync(&adapter->work); ++ ++#ifdef CONFIG_PALAU ++ be_sysfs_remove_group(adapter); ++#endif ++ ++ /* be_close() gets called if the device is open by unregister */ + unregister_netdev(adapter->netdev); + + be_clear(adapter); +@@ -2052,36 +3510,203 @@ static void __devexit be_remove(struct pci_dev *pdev) + + be_ctrl_cleanup(adapter); + +- if (adapter->msix_enabled) { +- pci_disable_msix(adapter->pdev); +- adapter->msix_enabled = false; +- } ++ kfree(adapter->vf_cfg); ++ be_sriov_disable(adapter); ++ ++ be_msix_disable(adapter); + + pci_set_drvdata(pdev, NULL); + pci_release_regions(pdev); + pci_disable_device(pdev); +- ++ be_netif_napi_del(adapter->netdev); + free_netdev(adapter->netdev); + } + +-static int be_hw_up(struct be_adapter *adapter) ++static void be_pcie_slot_check(struct be_adapter *adapter) ++{ ++ u32 curr, max, width, max_wd, speed, max_sp; ++ ++ pci_read_config_dword(adapter->pdev, PCICFG_PCIE_LINK_STATUS_OFFSET, ++ &curr); ++ width = (curr >> PCIE_LINK_STATUS_NEG_WIDTH_SHIFT) & ++ PCIE_LINK_STATUS_NEG_WIDTH_MASK; ++ speed = (curr >> PCIE_LINK_STATUS_SPEED_SHIFT) & ++ PCIE_LINK_STATUS_SPEED_MASK; ++ ++ pci_read_config_dword(adapter->pdev, PCICFG_PCIE_LINK_CAP_OFFSET, ++ &max); ++ max_wd = (max >> PCIE_LINK_CAP_MAX_WIDTH_SHIFT) & ++ PCIE_LINK_CAP_MAX_WIDTH_MASK; ++ max_sp = (max >> PCIE_LINK_CAP_MAX_SPEED_SHIFT) & ++ PCIE_LINK_CAP_MAX_SPEED_MASK; ++ ++ if (width < max_wd || speed < max_sp) ++ dev_warn(&adapter->pdev->dev, ++ "Found network device in a Gen%s x%d PCIe slot. It " ++ "should be in a Gen2 x%d slot for best performance\n", ++ speed < max_sp ? "1" : "2", width, max_wd); ++} ++ ++static int be_get_ioctl_version(char *fw_version) { ++ char *str[4]; ++ int i; ++ int val[4]; ++ char *endptr; ++ ++ if(!fw_version) ++ return 0; ++ for(i=0; i<3; i++) { ++ str[i] = strsep(&fw_version, "."); ++ val[i] = simple_strtol(str[i], &endptr, 10); ++ } ++ ++ if (val[0]>4 || (val[0]>3 && val[2]>143)) ++ return 1; ++ return 0; ++} ++ ++static int be_get_port_names(struct be_adapter *adapter) + { + int status; ++ int ver; + +- status = be_cmd_POST(adapter); ++ status = be_cmd_get_fw_ver(adapter, ++ adapter->fw_ver, NULL); + if (status) + return status; ++ ver = be_get_ioctl_version(adapter->fw_ver); ++ if (ver && (adapter->generation == BE_GEN3)) ++ status = be_cmd_query_port_names_v1(adapter, ++ adapter->port_name); ++ else ++ status = be_cmd_query_port_names_v0(adapter, ++ adapter->port_name); ++ return status; ++} + +- status = be_cmd_reset_function(adapter); ++static int be_get_config(struct be_adapter *adapter) ++{ ++ int status; ++ u8 mac[ETH_ALEN]; ++ ++ status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, ++ &adapter->function_mode, ++ &adapter->function_caps); + if (status) + return status; + +- status = be_cmd_get_fw_ver(adapter, adapter->fw_ver); ++ status = be_cmd_get_cntl_attributes(adapter); + if (status) + return status; + +- status = be_cmd_query_fw_cfg(adapter, +- &adapter->port_num, &adapter->cap); ++ memset(mac, 0, ETH_ALEN); ++ be_pcie_slot_check(adapter); ++ ++ if (be_physfn(adapter)) { ++ status = be_cmd_mac_addr_query(adapter, mac, ++ MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0); ++ ++ if (status) ++ return status; ++ ++ if (!is_valid_ether_addr(mac)) ++ return -EADDRNOTAVAIL; ++ ++ memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); ++ memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); ++ } ++ ++ if (adapter->function_mode & FLEX10_MODE) ++ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/8; ++ else ++ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED; ++ ++ return 0; ++} ++ ++static int be_dev_family_check(struct be_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ u32 sli_intf = 0, if_type; ++ ++ switch (pdev->device) { ++ case BE_DEVICE_ID1: ++ case OC_DEVICE_ID1: ++ adapter->generation = BE_GEN2; ++ break; ++ case BE_DEVICE_ID2: ++ case OC_DEVICE_ID2: ++ adapter->generation = BE_GEN3; ++ break; ++ case OC_DEVICE_ID3: ++ pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf); ++ if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >> ++ SLI_INTF_IF_TYPE_SHIFT; ++ ++ if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) || ++ if_type != 0x02) { ++ dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n"); ++ return -EINVAL; ++ } ++ if (num_vfs > 0) { ++ dev_err(&pdev->dev, "VFs not supported\n"); ++ return -EINVAL; ++ } ++ adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >> ++ SLI_INTF_FAMILY_SHIFT); ++ adapter->generation = BE_GEN3; ++ break; ++ default: ++ adapter->generation = 0; ++ } ++ return 0; ++} ++ ++static int lancer_wait_ready(struct be_adapter *adapter) ++{ ++#define SLIPORT_READY_TIMEOUT 500 ++ u32 sliport_status; ++ int status = 0, i; ++ ++ for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) { ++ sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); ++ if (sliport_status & SLIPORT_STATUS_RDY_MASK) ++ break; ++ ++ msleep(20); ++ } ++ ++ if (i == SLIPORT_READY_TIMEOUT) ++ status = -1; ++ ++ return status; ++} ++ ++static int lancer_test_and_set_rdy_state(struct be_adapter *adapter) ++{ ++ int status; ++ u32 sliport_status, err, reset_needed; ++ status = lancer_wait_ready(adapter); ++ if (!status) { ++ sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); ++ err = sliport_status & SLIPORT_STATUS_ERR_MASK; ++ reset_needed = sliport_status & SLIPORT_STATUS_RN_MASK; ++ if (err && reset_needed) { ++ iowrite32(SLI_PORT_CONTROL_IP_MASK, ++ adapter->db + SLIPORT_CONTROL_OFFSET); ++ ++ /* check adapter has corrected the error */ ++ status = lancer_wait_ready(adapter); ++ sliport_status = ioread32(adapter->db + ++ SLIPORT_STATUS_OFFSET); ++ sliport_status &= (SLIPORT_STATUS_ERR_MASK | ++ SLIPORT_STATUS_RN_MASK); ++ if (status || sliport_status) ++ status = -1; ++ } else if (err || reset_needed) { ++ status = -1; ++ } ++ } + return status; + } + +@@ -2091,7 +3716,7 @@ static int __devinit be_probe(struct pci_dev *pdev, + int status = 0; + struct be_adapter *adapter; + struct net_device *netdev; +- u8 mac[ETH_ALEN]; ++ u32 en; + + status = pci_enable_device(pdev); + if (status) +@@ -2102,31 +3727,22 @@ static int __devinit be_probe(struct pci_dev *pdev, + goto disable_dev; + pci_set_master(pdev); + +- netdev = alloc_etherdev(sizeof(struct be_adapter)); ++ netdev = alloc_etherdev_mq(sizeof(struct be_adapter), MAX_TX_QS); + if (netdev == NULL) { + status = -ENOMEM; + goto rel_reg; + } + adapter = netdev_priv(netdev); + +- switch (pdev->device) { +- case BE_DEVICE_ID1: +- case OC_DEVICE_ID1: +- adapter->generation = BE_GEN2; +- break; +- case BE_DEVICE_ID2: +- case OC_DEVICE_ID2: +- adapter->generation = BE_GEN3; +- break; +- default: +- adapter->generation = 0; +- } +- + adapter->pdev = pdev; ++ ++ status = be_dev_family_check(adapter); ++ if (status) ++ goto free_netdev; ++ + pci_set_drvdata(pdev, adapter); + adapter->netdev = netdev; +- +- be_msix_enable(adapter); ++ SET_NETDEV_DEV(netdev, &pdev->dev); + + status = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (!status) { +@@ -2139,46 +3755,150 @@ static int __devinit be_probe(struct pci_dev *pdev, + } + } + ++ be_sriov_enable(adapter); ++ if (adapter->num_vfs > 0) { ++ adapter->vf_cfg = kcalloc(adapter->num_vfs, ++ sizeof(struct be_vf_cfg), GFP_KERNEL); ++ ++ if (!adapter->vf_cfg) ++ goto free_netdev; ++ } ++ + status = be_ctrl_init(adapter); + if (status) +- goto free_netdev; ++ goto free_vf_cfg; ++ ++ if (lancer_chip(adapter)) { ++ status = lancer_test_and_set_rdy_state(adapter); ++ if (status) { ++ dev_err(&pdev->dev, "Adapter in non recoverable error\n"); ++ goto ctrl_clean; ++ } ++ } ++ ++ /* sync up with fw's ready state */ ++ if (be_physfn(adapter)) { ++ status = be_cmd_POST(adapter); ++ if (status) ++ goto ctrl_clean; ++ } ++ ++ /* tell fw we're ready to fire cmds */ ++ status = be_cmd_fw_init(adapter); ++ if (status) ++ goto ctrl_clean; ++ ++ status = be_cmd_reset_function(adapter); ++ if (status) ++ goto ctrl_clean; + + status = be_stats_init(adapter); + if (status) + goto ctrl_clean; + +- status = be_hw_up(adapter); ++ status = be_get_config(adapter); + if (status) + goto stats_clean; + +- status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, +- true /* permanent */, 0); +- if (status) +- goto stats_clean; +- memcpy(netdev->dev_addr, mac, ETH_ALEN); ++ /* This bit is zero in normal boot case, but in crash kernel case this ++ is not cleared. clear this bit here, until we are ready with the irqs ++ i.e in be_open call.*/ ++ if (!lancer_chip(adapter)) ++ be_intr_set(adapter, false); ++ ++ if (msix) ++ be_msix_enable(adapter); + + INIT_DELAYED_WORK(&adapter->work, be_worker); +- be_netdev_init(netdev); +- SET_NETDEV_DEV(netdev, &adapter->pdev->dev); + + status = be_setup(adapter); + if (status) +- goto stats_clean; ++ goto msix_disable; ++ ++ /* Initilize the link status to -1 */ ++ adapter->link_status = -1; ++ ++ status = be_netdev_init(netdev); ++ if (status) ++ goto unsetup; ++ + status = register_netdev(netdev); + if (status != 0) + goto unsetup; + +- dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); ++ be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); ++ ++ if (be_physfn(adapter) && adapter->num_vfs) { ++ u8 mac_speed; ++ int link_status; ++ u16 def_vlan, vf, lnk_speed; ++ ++ status = be_vf_eth_addr_config(adapter); ++ if (status) ++ goto unreg_netdev; ++ ++ for (vf = 0; vf < adapter->num_vfs; vf++) { ++ status = be_cmd_get_hsw_config(adapter, &def_vlan, ++ vf + 1, adapter->vf_cfg[vf].vf_if_handle); ++ if (!status) ++ adapter->vf_cfg[vf].vf_def_vid = def_vlan; ++ else ++ goto unreg_netdev; ++ ++ status = be_cmd_link_status_query(adapter, &link_status, ++ &mac_speed, &lnk_speed, vf + 1); ++ if (!status) ++ adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; ++ else ++ goto unreg_netdev; ++ } ++ } ++ if (be_physfn(adapter)) { ++ /* Temp fix ofr bug# 23034. Till ARM ++ * f/w fixes privilege lvl */ ++ be_get_port_names(adapter); ++ } ++ ++ /* Enable Vlan capability based on privileges. ++ * PF will have Vlan capability anyway. */ ++ be_cmd_get_fn_privileges(adapter, &en, 0); ++ ++ if ((en & (BE_PRIV_FILTMGMT | BE_PRIV_VHADM | BE_PRIV_DEVCFG)) || ++ be_physfn(adapter)) ++ netdev->features |= NETIF_F_HW_VLAN_FILTER; ++ else ++ netdev->features |= NETIF_F_VLAN_CHALLENGED; ++ ++ dev_info(&pdev->dev, "%s: numa node %d\n", netdev->name, ++ dev_to_node(&pdev->dev)); ++ dev_info(&pdev->dev, "%s %s \"%s\" port %d\n", nic_name(pdev), ++ (adapter->port_num > 1 ? "1Gbps NIC" : "10Gbps NIC"), ++ adapter->model_number, adapter->hba_port_num); ++ ++ ++#ifdef CONFIG_PALAU ++ be_sysfs_create_group(adapter); ++#endif ++ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; + ++unreg_netdev: ++ unregister_netdev(netdev); + unsetup: + be_clear(adapter); ++msix_disable: ++ be_msix_disable(adapter); + stats_clean: + be_stats_cleanup(adapter); + ctrl_clean: + be_ctrl_cleanup(adapter); ++free_vf_cfg: ++ kfree(adapter->vf_cfg); + free_netdev: +- free_netdev(adapter->netdev); ++ be_sriov_disable(adapter); ++ be_netif_napi_del(netdev); ++ free_netdev(netdev); ++ pci_set_drvdata(pdev, NULL); + rel_reg: + pci_release_regions(pdev); + disable_dev: +@@ -2193,6 +3913,10 @@ 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->netdev; + ++ cancel_delayed_work_sync(&adapter->work); ++ if (adapter->wol) ++ be_setup_wol(adapter, true); ++ + netif_device_detach(netdev); + if (netif_running(netdev)) { + rtnl_lock(); +@@ -2202,6 +3926,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) + be_cmd_get_flow_control(adapter, &adapter->tx_fc, &adapter->rx_fc); + be_clear(adapter); + ++ be_msix_disable(adapter); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +@@ -2223,6 +3948,12 @@ static int be_resume(struct pci_dev *pdev) + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + ++ be_msix_enable(adapter); ++ /* tell fw we're ready to fire cmds */ ++ status = be_cmd_fw_init(adapter); ++ if (status) ++ return status; ++ + be_setup(adapter); + if (netif_running(netdev)) { + rtnl_lock(); +@@ -2230,28 +3961,152 @@ static int be_resume(struct pci_dev *pdev) + rtnl_unlock(); + } + netif_device_attach(netdev); ++ ++ if (adapter->wol) ++ be_setup_wol(adapter, false); ++ ++ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; + } + ++/* ++ * An FLR will stop BE from DMAing any data. ++ */ ++static void be_shutdown(struct pci_dev *pdev) ++{ ++ struct be_adapter *adapter = pci_get_drvdata(pdev); ++ ++ if (!adapter) ++ return; ++ ++ cancel_delayed_work_sync(&adapter->work); ++ ++ netif_device_detach(adapter->netdev); ++ ++ if (adapter->wol) ++ be_setup_wol(adapter, true); ++ ++ be_cmd_reset_function(adapter); ++ ++ pci_disable_device(pdev); ++} ++ ++static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, ++ pci_channel_state_t state) ++{ ++ struct be_adapter *adapter = pci_get_drvdata(pdev); ++ struct net_device *netdev = adapter->netdev; ++ ++ dev_err(&adapter->pdev->dev, "EEH error detected\n"); ++ ++ adapter->eeh_err = true; ++ ++ netif_device_detach(netdev); ++ ++ if (netif_running(netdev)) { ++ rtnl_lock(); ++ be_close(netdev); ++ rtnl_unlock(); ++ } ++ be_clear(adapter); ++ ++ if (state == pci_channel_io_perm_failure) ++ return PCI_ERS_RESULT_DISCONNECT; ++ ++ pci_disable_device(pdev); ++ ++ return PCI_ERS_RESULT_NEED_RESET; ++} ++ ++static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) ++{ ++ struct be_adapter *adapter = pci_get_drvdata(pdev); ++ int status; ++ ++ dev_info(&adapter->pdev->dev, "EEH reset\n"); ++ adapter->eeh_err = false; ++ ++ status = pci_enable_device(pdev); ++ if (status) ++ return PCI_ERS_RESULT_DISCONNECT; ++ ++ pci_set_master(pdev); ++ pci_set_power_state(pdev, 0); ++ pci_restore_state(pdev); ++ ++ /* Check if card is ok and fw is ready */ ++ status = be_cmd_POST(adapter); ++ if (status) ++ return PCI_ERS_RESULT_DISCONNECT; ++ ++ return PCI_ERS_RESULT_RECOVERED; ++} ++ ++static void be_eeh_resume(struct pci_dev *pdev) ++{ ++ int status = 0; ++ struct be_adapter *adapter = pci_get_drvdata(pdev); ++ struct net_device *netdev = adapter->netdev; ++ ++ dev_info(&adapter->pdev->dev, "EEH resume\n"); ++ ++ pci_save_state(pdev); ++ ++ /* tell fw we're ready to fire cmds */ ++ status = be_cmd_fw_init(adapter); ++ if (status) ++ goto err; ++ ++ status = be_setup(adapter); ++ if (status) ++ goto err; ++ ++ if (netif_running(netdev)) { ++ status = be_open(netdev); ++ if (status) ++ goto err; ++ } ++ netif_device_attach(netdev); ++ return; ++err: ++ dev_err(&adapter->pdev->dev, "EEH resume failed\n"); ++ return; ++} ++ ++static struct pci_error_handlers be_eeh_handlers = { ++ .error_detected = be_eeh_err_detected, ++ .slot_reset = be_eeh_reset, ++ .resume = be_eeh_resume, ++}; ++ + static struct pci_driver be_driver = { + .name = DRV_NAME, + .id_table = be_dev_ids, + .probe = be_probe, + .remove = be_remove, + .suspend = be_suspend, +- .resume = be_resume ++ .resume = be_resume, ++ .shutdown = be_shutdown, ++ .err_handler = &be_eeh_handlers + }; + + static int __init be_init_module(void) + { +- if (rx_frag_size != 8192 && rx_frag_size != 4096 +- && rx_frag_size != 2048) { ++ if (rx_frag_size != 8192 && rx_frag_size != 4096 && ++ rx_frag_size != 2048) { + printk(KERN_WARNING DRV_NAME + " : Module param rx_frag_size must be 2048/4096/8192." + " Using 2048\n"); + rx_frag_size = 2048; + } + ++ if (!msix && num_vfs > 0) { ++ printk(KERN_WARNING DRV_NAME ++ " : MSIx required for num_vfs > 0. Ignoring msix=0\n"); ++ msix = 1; ++ } ++ ++ + return pci_register_driver(&be_driver); + } + module_init(be_init_module); +diff --git a/drivers/net/benet/be_misc.c b/drivers/net/benet/be_misc.c +new file mode 100644 +index 0000000..4ab499f +--- /dev/null ++++ b/drivers/net/benet/be_misc.c +@@ -0,0 +1,106 @@ ++/* ++ * Copyright (C) 2005 - 2011 Emulex ++ * 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@emulex.com ++ * ++ * Emulex ++ * 3333 Susan Street ++ * Costa Mesa, CA 92626 ++ */ ++#include "be.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) ++static ssize_t ++flash_fw_store(struct class_device *cd, const char *buf, size_t len) ++{ ++ struct be_adapter *adapter = ++ netdev_priv(container_of(cd, struct net_device, class_dev)); ++ char file_name[ETHTOOL_FLASH_MAX_FILENAME]; ++ int status; ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; ++ strncpy(file_name, buf, (ETHTOOL_FLASH_MAX_FILENAME - 1)); ++ ++ /* Removing new-line char given by sysfs */ ++ file_name[strlen(file_name) - 1] = '\0'; ++ ++ status = be_load_fw(adapter, file_name); ++ if (!status) ++ return len; ++ else ++ return status; ++} ++ ++static CLASS_DEVICE_ATTR(flash_fw, S_IWUSR, NULL, flash_fw_store); ++ ++static struct attribute *benet_attrs[] = { ++ &class_device_attr_flash_fw.attr, ++ NULL, ++}; ++#else ++ ++static ssize_t ++flash_fw_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct be_adapter *adapter = ++ netdev_priv(container_of(dev, struct net_device, dev)); ++ char file_name[ETHTOOL_FLASH_MAX_FILENAME]; ++ int status; ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; ++ strncpy(file_name, buf, (ETHTOOL_FLASH_MAX_FILENAME - 1)); ++ ++ /* Removing new-line char given by sysfs */ ++ file_name[strlen(file_name) - 1] = '\0'; ++ ++ status = be_load_fw(adapter, file_name); ++ if (!status) ++ return len; ++ else ++ return status; ++} ++ ++static DEVICE_ATTR(flash_fw, S_IWUSR, NULL, flash_fw_store); ++ ++static struct attribute *benet_attrs[] = { ++ &dev_attr_flash_fw.attr, ++ NULL, ++}; ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) ++#define CLASS_DEV class_dev ++#else ++#define CLASS_DEV dev ++#endif ++ ++static struct attribute_group benet_attr_group = {.attrs = benet_attrs }; ++ ++void be_sysfs_create_group(struct be_adapter *adapter) ++{ ++ int status; ++ ++ status = sysfs_create_group(&adapter->netdev->CLASS_DEV.kobj, ++ &benet_attr_group); ++ if (status) ++ dev_err(&adapter->pdev->dev, "Could not create sysfs group\n"); ++} ++ ++void be_sysfs_remove_group(struct be_adapter *adapter) ++{ ++ sysfs_remove_group(&adapter->netdev->CLASS_DEV.kobj, &benet_attr_group); ++} +diff --git a/drivers/net/benet/be_proc.c b/drivers/net/benet/be_proc.c +new file mode 100644 +index 0000000..0bfdb3b +--- /dev/null ++++ b/drivers/net/benet/be_proc.c +@@ -0,0 +1,513 @@ ++/* ++ * Copyright (C) 2005 - 2011 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 <linux/proc_fs.h> ++#include "be.h" ++ ++char *be_adpt_name[] = { ++ "driver/be2net0", ++ "driver/be2net1", ++ "driver/be2net2", ++ "driver/be2net3", ++ "driver/be2net4", ++ "driver/be2net5", ++ "driver/be2net6", ++ "driver/be2net7" ++}; ++ ++#define MAX_BE_DEVICES 8 ++struct proc_dir_entry *be_proc_dir[MAX_BE_DEVICES]; ++ ++/*File to read Eth Ring Information */ ++#define BE_ETH_RING_FILE "eth_ring" ++#define BE_DRVR_STAT_FILE "drvr_stat" ++ ++/* ++ * this file enables user to read a 32 bit CSR register. ++ * to read 32 bit value of a register at offset 0x1234, ++ * first write the offset 0x1234 (echo "0x1234") in ++ * the file and then read the value from this file. ++ * the written offset is latched until another value is written ++ */ ++#define BE_CSR_R_FILE "csrr" ++/* ++ * this file enables user to write to a 32 bit CSR register. ++ * to write a value 0xdeadbeef to a register at offset 0x1234, ++ * write 0x1234 0xdeadbeef (echo "0x1234 0xdeadbeeb") to ++ * the file. ++ */ ++#define BE_CSR_W_FILE "csrw" ++ ++#define BE_PROC_MODE 0600 ++ ++static char read_eth_ring_buf[4096]; ++static int read_eth_ring_count; ++ ++/* ++ * Get Various Eth Ring Properties ++ */ ++static int proc_eth_read_ring(char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ int i, n; ++ char *p = read_eth_ring_buf; ++ struct be_adapter *adapter = (struct be_adapter *) data; ++ ++ if (off == 0) { ++ /* Reset read_eth_ring_count */ ++ read_eth_ring_count = 0; ++ ++ n = sprintf(p, " PhyAddr VirtAddr Size TotalEntries ProducerIndex ConsumerIndex NumUsed\n"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, " ------- -------- ---- ------------ ------------- ------------- -------\n"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, "%s", "EthSendRing"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, " %7lx %8p %4u %12u %13u %13u %7u \n", ++ (long) adapter->tx_obj.q.dma_mem.dma, ++ (void *)adapter->tx_obj.q.dma_mem.va, ++ (u32) (adapter->tx_obj.q.len * ++ sizeof(struct be_eth_wrb)), ++ adapter->tx_obj.q.len, adapter->tx_obj.q.head, ++ adapter->tx_obj.q.tail, ++ atomic_read(&adapter->tx_obj.q.used)); ++ ++ p += n; ++ read_eth_ring_count += n; ++ ++ /* Get Eth Send Compl Queue Details */ ++ n = sprintf(p, "%s", "EthSendCmplRing"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, " %7lx %8p %4u %12u %13s %13u %7s\n", ++ (long)adapter->tx_obj.cq.dma_mem.dma, ++ (void *)adapter->tx_obj.cq.dma_mem.va, ++ (u32) (adapter->tx_obj.cq.len * ++ sizeof(struct be_eth_tx_compl)), ++ adapter->tx_obj.cq.len, "NA", ++ adapter->tx_obj.cq.tail, "NA"); ++ ++ p += n; ++ read_eth_ring_count += n; ++ /* Get Eth Rx Queue Details */ ++ n = sprintf(p, "%s", "EthRxRing"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, " %7lx %8p %4u %12u %13u %13s %7u \n", ++ (long)adapter->rx_obj.q.dma_mem.dma, ++ (void *)adapter->rx_obj.q.dma_mem.va, ++ (u32) (adapter->rx_obj.q.len * ++ sizeof(struct be_eth_rx_d)), ++ adapter->rx_obj.q.len, adapter->rx_obj.q.head,"NA", ++ atomic_read(&adapter->rx_obj.q.used)); ++ p += n; ++ read_eth_ring_count += n; ++ ++ /* Get Eth Unicast Rx Compl Queue Details */ ++ n = sprintf(p, "%s", "EthRxCmplRing"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, " %7lx %8p %4u %12u %13s %13u %7s\n", ++ (long)adapter->rx_obj.cq.dma_mem.dma, ++ (void *)adapter->rx_obj.cq.dma_mem.va, ++ (u32) (adapter->rx_obj.cq.len * ++ sizeof(struct be_eth_rx_compl)), ++ adapter->rx_obj.cq.len, "NA", ++ adapter->rx_obj.cq.tail, "NA"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ /* Get Eth Event Queue Details */ ++ n = sprintf(p, "%s", "EthTxEventRing"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, ++ " %7lx %8p %4u %12u %13s %13u %7s\n", ++ (long) adapter->tx_eq.q.dma_mem.dma, ++ (void *)adapter->tx_eq.q.dma_mem.va, ++ (u32) (adapter->tx_eq.q.len * ++ sizeof(struct be_eq_entry)), ++ adapter->tx_eq.q.len, "NA", ++ adapter->tx_eq.q.tail, "NA"); ++ ++ p += n; ++ read_eth_ring_count += n; ++ ++ /* Get Eth Event Queue Details */ ++ n = sprintf(p, "%s", "EthRxEventRing"); ++ p += n; ++ read_eth_ring_count += n; ++ ++ n = sprintf(p, ++ " %7lx %8p %4u %12u %13s %13u %7s\n", ++ (long) adapter->rx_eq.q.dma_mem.dma, ++ (void *)adapter->rx_eq.q.dma_mem.va, ++ (u32) (adapter->rx_eq.q.len * ++ sizeof(struct be_eq_entry)), ++ adapter->rx_eq.q.len, "NA", ++ adapter->rx_eq.q.tail, "NA"); ++ ++ p += n; ++ read_eth_ring_count += n; ++ } ++ ++ *start = page; ++ /* copy whatever we can */ ++ if (count < (read_eth_ring_count - off)) { ++ i = count; ++ *eof = 0; /* More bytes left */ ++ } else { ++ i = read_eth_ring_count - off; ++ *eof = 1; /* Nothing left. indicate EOF */ ++ } ++ ++ memcpy(page, read_eth_ring_buf + off, i); ++ return (i); ++} ++ ++static int proc_eth_write_ring(struct file *file, ++ const char *buffer, unsigned long count, ++ void *data) ++{ ++ return (count); /* we do not support write */ ++} ++ ++/* ++ * read the driver stats. ++ */ ++static int proc_read_drvr_stat(char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ int n, lro_cp; ++ char *p = page; ++ struct be_adapter *adapter = (struct be_adapter *) data; ++ struct net_device *netdev = adapter->netdev; ++ ++ if (off == 0) { ++ n = sprintf(p, "interface = %s\n", netdev->name); ++ p += n; ++ n = sprintf(p, "tx_reqs = %d\n", ++ drvr_stats(adapter)->be_tx_reqs); ++ p += n; ++ n = sprintf(p, "tx_stops = %d\n", ++ drvr_stats(adapter)->be_tx_stops); ++ p += n; ++ n = sprintf(p, "fwd_reqs = %d\n", ++ drvr_stats(adapter)->be_fwd_reqs); ++ p += n; ++ n = sprintf(p, "tx_wrbs = %d\n", ++ drvr_stats(adapter)->be_tx_wrbs); ++ p += n; ++ n = sprintf(p, "rx_poll = %d\n", drvr_stats(adapter)->be_rx_polls); ++ p += n; ++ n = sprintf(p, "tx_events = %d\n", ++ drvr_stats(adapter)->be_tx_events); ++ p += n; ++ n = sprintf(p, "rx_events = %d\n", ++ drvr_stats(adapter)->be_rx_events); ++ p += n; ++ n = sprintf(p, "tx_compl = %d\n", ++ drvr_stats(adapter)->be_tx_compl); ++ p += n; ++ n = sprintf(p, "rx_compl = %d\n", ++ drvr_stats(adapter)->be_rx_compl); ++ p += n; ++ n = sprintf(p, "ethrx_post_fail = %d\n", ++ drvr_stats(adapter)->be_ethrx_post_fail); ++ p += n; ++ n = sprintf(p, "802.3_dropped_frames = %d\n", ++ drvr_stats(adapter)->be_802_3_dropped_frames); ++ p += n; ++ n = sprintf(p, "802.3_malformed_frames = %d\n", ++ drvr_stats(adapter)->be_802_3_malformed_frames); ++ p += n; ++ n = sprintf(p, "eth_tx_rate = %d\n", ++ drvr_stats(adapter)->be_tx_rate); ++ p += n; ++ n = sprintf(p, "eth_rx_rate = %d\n", ++ drvr_stats(adapter)->be_rx_rate); ++ p += n; ++ ++ lro_cp = (drvr_stats(adapter)->be_lro_hgram_data[0] + ++ drvr_stats(adapter)->be_lro_hgram_data[1] + ++ drvr_stats(adapter)->be_lro_hgram_data[2] + ++ drvr_stats(adapter)->be_lro_hgram_data[3] + ++ drvr_stats(adapter)->be_lro_hgram_data[4] + ++ drvr_stats(adapter)->be_lro_hgram_data[5] + ++ drvr_stats(adapter)->be_lro_hgram_data[6] + ++ drvr_stats(adapter)->be_lro_hgram_data[7])/100; ++ lro_cp = (lro_cp == 0) ? 1 : lro_cp; /* avoid divide by 0 */ ++ n = sprintf(p, ++ "LRO data count %% histogram (1, 2-3, 4-5,..,>=16) = " ++ "%d, %d, %d, %d - %d, %d, %d, %d\n", ++ drvr_stats(adapter)->be_lro_hgram_data[0]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[1]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[2]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[3]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[4]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[5]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[6]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_data[7]/lro_cp); ++ p += n; ++ ++ lro_cp = (drvr_stats(adapter)->be_lro_hgram_ack[0] + ++ drvr_stats(adapter)->be_lro_hgram_ack[1] + ++ drvr_stats(adapter)->be_lro_hgram_ack[2] + ++ drvr_stats(adapter)->be_lro_hgram_ack[3] + ++ drvr_stats(adapter)->be_lro_hgram_ack[4] + ++ drvr_stats(adapter)->be_lro_hgram_ack[5] + ++ drvr_stats(adapter)->be_lro_hgram_ack[6] + ++ drvr_stats(adapter)->be_lro_hgram_ack[7])/100; ++ lro_cp = (lro_cp == 0) ? 1 : lro_cp; /* avoid divide by 0 */ ++ n = sprintf(p, ++ "LRO ack count %% histogram (1, 2-3, 4-5,..,>=16) = " ++ "%d, %d, %d, %d - %d, %d, %d, %d\n", ++ drvr_stats(adapter)->be_lro_hgram_ack[0]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[1]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[2]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[3]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[4]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[5]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[6]/lro_cp, ++ drvr_stats(adapter)->be_lro_hgram_ack[7]/lro_cp); ++ p += n; ++ n = sprintf(p, "rx_eq_delay = %d \n", adapter->rx_eq.cur_eqd); ++ p += n; ++ n = sprintf(p, "rx frags per sec=%d \n", ++ drvr_stats(adapter)->be_rx_fps); ++ p += n; ++ ++ } ++ *eof = 1; ++ return (p - page); ++} ++ ++static int proc_write_drvr_stat(struct file *file, ++ const char *buffer, unsigned long count, ++ void *data) ++{ ++ struct be_adapter *adapter = (struct be_adapter *) data; ++ ++ memset(&(adapter->stats.drvr_stats), 0, ++ sizeof(adapter->stats.drvr_stats)); ++ return (count); /* we do not support write */ ++} ++ ++#if 0 ++/* the following are some of the functions that are needed here ++ * until all initializations are done by MPU. ++ */ ++ ++u32 ++CsrReadDr(void* BaseAddress, u32 Offset) ++{ ++ u32 *rp; ++ ++ rp = (u32 *) (((u8 *) BaseAddress) + Offset); ++ return (*rp); ++} ++ ++/*! ++ ++@brief ++ This routine writes to a register located within the CSR ++ space for a given function object. ++ ++@param ++ FuncObj - Pointer to the function object to read from. ++ ++@param ++ Offset - The Offset (in bytes) to write to within the function's CSR space. ++ ++@param ++ Value - The value to write to the register. ++ ++@return ++ ++@note ++ IRQL: any ++ ++*/ ++void ++CsrWriteDr(void* BaseAddress, u32 Offset, u32 Value) ++{ ++ u32 *Register; ++ ++ Register = (u32 *) (((u8 *) BaseAddress) + Offset); ++ ++ //TRACE(DL_INFO, "CsrWrite[ %X ] <= %X", Register, Value); ++ *Register = Value; ++} ++u32 be_proc_csrr_offset = -1; /* to latch the offset of next CSR Read req. */ ++ ++/* ++ * read the csr_r file. return the 32 bit register value from ++ * CSR space at offset latched in the global location ++ * be_proc_csrr_offset ++ */ ++static int proc_read_csr_r(char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ struct be_adapter * adapter = (struct be_adapter *)data; ++ u32 val; ++ int n = 0; ++ if (be_proc_csrr_offset == -1) ++ return -EINVAL; ++ ++ if (off == 0) { ++ /* read the CSR at offset be_proc_csrr_offset and return */ ++ val = CsrReadDr(adapter->csr_va, be_proc_csrr_offset); ++ n = sprintf(page, "0x%x\n", val); ++ } ++ *eof = 1; ++ return n; ++} ++ ++/* ++ * save the written value in be_proc_csrr_offset for next ++ * read from the file ++ */ ++static int proc_write_csr_r(struct file *file, ++ const char *buffer, unsigned long count, void *data) ++{ ++ char buf[64]; ++ u32 n; ++ ++ if (count > sizeof(buf) + 1) ++ return -EINVAL; ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ buf[count] = '\0'; ++ ++ n = simple_strtoul(buf, NULL, 16); ++ if (n < 0x50000) ++ be_proc_csrr_offset = n; ++ return (count); ++} ++ ++/* ++ * return the latched offset for reading the csr_r file. ++ */ ++static int proc_read_csr_w(char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ ++ *eof = 1; ++ return sprintf(page, "0x%x\n", be_proc_csrr_offset); ++} ++ ++/* ++ * the incoming string is of the form "<offset> <value>" ++ * where the offset is the offset of the register to be written ++ * and value is the value to be written. ++ */ ++static int proc_write_csr_w(struct file *file, ++ const char *buffer, unsigned long count, ++ void *data) ++{ ++ char buf[64]; ++ char *p; ++ u32 n, val; ++ struct be_adapter * adapter = (struct be_adapter *)data; ++ ++ if (count > sizeof(buf) + 1) ++ return -EINVAL; ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ buf[count] = '\0'; ++ ++ n = simple_strtoul(buf, &p, 16); ++ if (n > 0x50000) ++ return -EINVAL; ++ ++ /* now get the actual value to be written */ ++ while (*p == ' ' || *p == '\t') ++ p++; ++ val = simple_strtoul(p, NULL, 16); ++ CsrWriteDr(adapter->csr_va, n, val); ++ return (count); ++} ++#endif ++ ++void be_init_procfs(struct be_adapter *adapter, int adapt_num) ++{ ++ static struct proc_dir_entry *pde; ++ ++ if (adapt_num > MAX_BE_DEVICES - 1) ++ return; ++ ++ /* create directory */ ++ be_proc_dir[adapt_num] = ++ proc_mkdir(be_adpt_name[adapt_num], NULL); ++ if (be_proc_dir[adapt_num]) { ++ (be_proc_dir[adapt_num])->owner = THIS_MODULE; ++ } ++ ++ pde = create_proc_entry(BE_ETH_RING_FILE, BE_PROC_MODE, ++ be_proc_dir[adapt_num]); ++ if (pde) { ++ pde->read_proc = proc_eth_read_ring; ++ pde->write_proc = proc_eth_write_ring; ++ pde->data = adapter; ++ pde->owner = THIS_MODULE; ++ } ++ ++ pde = create_proc_entry(BE_DRVR_STAT_FILE, BE_PROC_MODE, ++ be_proc_dir[adapt_num]); ++ if (pde) { ++ pde->read_proc = proc_read_drvr_stat; ++ pde->write_proc = proc_write_drvr_stat; ++ pde->data = adapter; ++ pde->owner = THIS_MODULE; ++ } ++ ++#if 0 ++ if ((pde = create_proc_entry(BE_CSR_R_FILE, BE_PROC_MODE, be_proc_dir[adapt_num]))) { ++ pde->read_proc = proc_read_csr_r; ++ pde->write_proc = proc_write_csr_r; ++ pde->data = adapter; ++ pde->owner = THIS_MODULE; ++ } ++ ++ if ((pde = create_proc_entry(BE_CSR_W_FILE, BE_PROC_MODE, be_proc_dir[adapt_num]))) { ++ pde->read_proc = proc_read_csr_w; ++ pde->write_proc = proc_write_csr_w; ++ pde->data = adapter; ++ pde->owner = THIS_MODULE; ++ } ++#endif ++} ++ ++void be_cleanup_procfs(struct be_adapter *adapter, int adapt_num) ++{ ++ if (adapt_num > MAX_BE_DEVICES - 1) ++ return; ++ remove_proc_entry(BE_ETH_RING_FILE, be_proc_dir[adapt_num]); ++ remove_proc_entry(BE_DRVR_STAT_FILE, be_proc_dir[adapt_num]); ++ remove_proc_entry(BE_CSR_R_FILE, be_proc_dir[adapt_num]); ++ remove_proc_entry(BE_CSR_W_FILE, be_proc_dir[adapt_num]); ++ remove_proc_entry(be_adpt_name[adapt_num], NULL); ++} +diff --git a/drivers/net/benet/version.h b/drivers/net/benet/version.h +new file mode 100644 +index 0000000..c7ed692 +--- /dev/null ++++ b/drivers/net/benet/version.h +@@ -0,0 +1,51 @@ ++#define STR_BE_BRANCH "0"
++#define STR_BE_BUILD "479"
++#define STR_BE_DOT "0"
++#define STR_BE_MINOR "0"
++#define STR_BE_MAJOR "4"
++
++#define BE_BRANCH 0
++#define BE_BUILD 479
++#define BE_DOT 0
++#define BE_MINOR 0
++#define BE_MAJOR 4
++
++#define MGMT_BRANCH 0
++#define MGMT_BUILDNUM 479
++#define MGMT_MINOR 0
++#define MGMT_MAJOR 4
++
++#define BE_REDBOOT_VERSION "2.0.5.0"
++
++//start-auto
++#define BUILD_MONTH "12"
++#define BUILD_MONTH_NAME "December"
++#define BUILD_DAY "6"
++#define BUILD_YEAR "2011"
++#define BUILD_24HOUR "21"
++#define BUILD_12HOUR "9"
++#define BUILD_AM_PM "PM"
++#define BUILD_MIN "48"
++#define BUILD_SEC "05"
++#define BUILD_MONTH_NUMBER 12
++#define BUILD_DAY_NUMBER 6
++#define BUILD_YEAR_NUMBER 2011
++#define BUILD_24HOUR_NUMBER 21
++#define BUILD_12HOUR_NUMBER 9
++#define BUILD_MIN_NUMBER 48
++#define BUILD_SEC_NUMBER 5
++#undef MAJOR_BUILD
++#undef MINOR_BUILD
++#undef DOT_BUILD
++#define NUMBERED_BUILD
++#undef BRANCH_BUILD
++//end-auto
++
++#define ELX_FCOE_XROM_BIOS_VER "7.03a1"
++#define ELX_FCoE_X86_VER "4.02a1"
++#define ELX_FCoE_EFI_VER "5.01a1"
++#define ELX_FCoE_FCODE_VER "4.01a0"
++#define ELX_PXE_BIOS_VER "3.00a5"
++#define ELX_UEFI_NIC_VER "2.10A10"
++#define ELX_UEFI_FCODE_VER "1.10A0"
++#define ELX_ISCSI_BIOS_VER "1.00A8"
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4874b2b..67f8526 100644 --- a/drivers/net/bnx2.c @@ -40852,6 +54385,2347 @@ index ff4504c..b3604c3 100644 } int qdio_setup_perf_stats(void); +diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c +new file mode 100644 +index 0000000..7d18a18 +--- /dev/null ++++ b/drivers/scsi/3w-sas.c +@@ -0,0 +1,1933 @@ ++/* ++ 3w-sas.c -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. ++ ++ Written By: Adam Radford <linuxraid@lsi.com> ++ ++ Copyright (C) 2009 LSI 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; 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 ++ ++ Controllers supported by this driver: ++ ++ LSI 3ware 9750 6Gb/s SAS/SATA-RAID ++ ++ Bugs/Comments/Suggestions should be mailed to: ++ linuxraid@lsi.com ++ ++ For more information, goto: ++ http://www.lsi.com ++ ++ History ++ ------- ++ 3.26.00.000 - Initial driver release. ++*/ ++ ++#include <linux/module.h> ++#include <linux/reboot.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/moduleparam.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/delay.h> ++#include <linux/pci.h> ++#include <linux/time.h> ++#include <linux/mutex.h> ++#include <linux/smp_lock.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <scsi/scsi.h> ++#include <scsi/scsi_host.h> ++#include <scsi/scsi_tcq.h> ++#include <scsi/scsi_cmnd.h> ++#include "3w-sas.h" ++ ++/* Globals */ ++#define TW_DRIVER_VERSION "3.26.00.028-2.6.32RH" ++static TW_Device_Extension *twl_device_extension_list[TW_MAX_SLOT]; ++static unsigned int twl_device_extension_count; ++static int twl_major = -1; ++extern struct timezone sys_tz; ++ ++/* Module parameters */ ++MODULE_AUTHOR ("LSI"); ++MODULE_DESCRIPTION ("LSI 3ware SAS/SATA-RAID Linux Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(TW_DRIVER_VERSION); ++ ++static int use_msi = 0; ++module_param(use_msi, int, S_IRUGO); ++MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0"); ++ ++/* Function prototypes */ ++static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset); ++ ++/* Functions */ ++ ++/* This function returns AENs through sysfs */ ++static ssize_t twl_sysfs_aen_read(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *bin_attr, ++ char *outbuf, loff_t offset, size_t count) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct Scsi_Host *shost = class_to_shost(dev); ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata; ++ unsigned long flags = 0; ++ ssize_t ret; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ ++ spin_lock_irqsave(tw_dev->host->host_lock, flags); ++ ret = memory_read_from_buffer(outbuf, count, &offset, tw_dev->event_queue[0], sizeof(TW_Event) * TW_Q_LENGTH); ++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); ++ ++ return ret; ++} /* End twl_sysfs_aen_read() */ ++ ++/* aen_read sysfs attribute initializer */ ++static struct bin_attribute twl_sysfs_aen_read_attr = { ++ .attr = { ++ .name = "3ware_aen_read", ++ .mode = S_IRUSR, ++ }, ++ .size = 0, ++ .read = twl_sysfs_aen_read ++}; ++ ++/* This function returns driver compatibility info through sysfs */ ++static ssize_t twl_sysfs_compat_info(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *bin_attr, ++ char *outbuf, loff_t offset, size_t count) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct Scsi_Host *shost = class_to_shost(dev); ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata; ++ unsigned long flags = 0; ++ ssize_t ret; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ ++ spin_lock_irqsave(tw_dev->host->host_lock, flags); ++ ret = memory_read_from_buffer(outbuf, count, &offset, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info)); ++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); ++ ++ return ret; ++} /* End twl_sysfs_compat_info() */ ++ ++/* compat_info sysfs attribute initializer */ ++static struct bin_attribute twl_sysfs_compat_info_attr = { ++ .attr = { ++ .name = "3ware_compat_info", ++ .mode = S_IRUSR, ++ }, ++ .size = 0, ++ .read = twl_sysfs_compat_info ++}; ++ ++/* Show some statistics about the card */ ++static ssize_t twl_show_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct Scsi_Host *host = class_to_shost(dev); ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; ++ unsigned long flags = 0; ++ ssize_t len; ++ ++ spin_lock_irqsave(tw_dev->host->host_lock, flags); ++ len = snprintf(buf, PAGE_SIZE, "3w-sas Driver version: %s\n" ++ "Current commands posted: %4d\n" ++ "Max commands posted: %4d\n" ++ "Last sgl length: %4d\n" ++ "Max sgl length: %4d\n" ++ "Last sector count: %4d\n" ++ "Max sector count: %4d\n" ++ "SCSI Host Resets: %4d\n" ++ "AEN's: %4d\n", ++ TW_DRIVER_VERSION, ++ tw_dev->posted_request_count, ++ tw_dev->max_posted_request_count, ++ tw_dev->sgl_entries, ++ tw_dev->max_sgl_entries, ++ tw_dev->sector_count, ++ tw_dev->max_sector_count, ++ tw_dev->num_resets, ++ tw_dev->aen_count); ++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); ++ return len; ++} /* End twl_show_stats() */ ++ ++/* This function will set a devices queue depth */ ++static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth, ++ int reason) ++{ ++ if (reason != SCSI_QDEPTH_DEFAULT) ++ return -EOPNOTSUPP; ++ ++ if (queue_depth > TW_Q_LENGTH-2) ++ queue_depth = TW_Q_LENGTH-2; ++ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); ++ return queue_depth; ++} /* End twl_change_queue_depth() */ ++ ++/* stats sysfs attribute initializer */ ++static struct device_attribute twl_host_stats_attr = { ++ .attr = { ++ .name = "3ware_stats", ++ .mode = S_IRUGO, ++ }, ++ .show = twl_show_stats ++}; ++ ++/* Host attributes initializer */ ++static struct device_attribute *twl_host_attrs[] = { ++ &twl_host_stats_attr, ++ NULL, ++}; ++ ++/* This function will look up an AEN severity string */ ++static char *twl_aen_severity_lookup(unsigned char severity_code) ++{ ++ char *retval = NULL; ++ ++ if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || ++ (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) ++ goto out; ++ ++ retval = twl_aen_severity_table[severity_code]; ++out: ++ return retval; ++} /* End twl_aen_severity_lookup() */ ++ ++/* This function will queue an event */ ++static void twl_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) ++{ ++ u32 local_time; ++ struct timeval time; ++ TW_Event *event; ++ unsigned short aen; ++ char host[16]; ++ char *error_str; ++ ++ tw_dev->aen_count++; ++ ++ /* Fill out event info */ ++ event = tw_dev->event_queue[tw_dev->error_index]; ++ ++ host[0] = '\0'; ++ if (tw_dev->host) ++ sprintf(host, " scsi%d:", tw_dev->host->host_no); ++ ++ aen = le16_to_cpu(header->status_block.error); ++ memset(event, 0, sizeof(TW_Event)); ++ ++ event->severity = TW_SEV_OUT(header->status_block.severity__reserved); ++ do_gettimeofday(&time); ++ local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); ++ event->time_stamp_sec = local_time; ++ event->aen_code = aen; ++ event->retrieved = TW_AEN_NOT_RETRIEVED; ++ event->sequence_id = tw_dev->error_sequence_id; ++ tw_dev->error_sequence_id++; ++ ++ /* Check for embedded error string */ ++ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]); ++ ++ header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; ++ event->parameter_len = strlen(header->err_specific_desc); ++ memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + 1 + strlen(error_str)); ++ if (event->severity != TW_AEN_SEVERITY_DEBUG) ++ printk(KERN_WARNING "3w-sas:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", ++ host, ++ twl_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)), ++ TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, error_str, ++ header->err_specific_desc); ++ else ++ tw_dev->aen_count--; ++ ++ tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH; ++} /* End twl_aen_queue_event() */ ++ ++/* This function will attempt to post a command packet to the board */ ++static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id) ++{ ++ dma_addr_t command_que_value; ++ ++ command_que_value = tw_dev->command_packet_phys[request_id]; ++ command_que_value += TW_COMMAND_OFFSET; ++ ++ /* First write upper 4 bytes */ ++ writel((u32)((u64)command_que_value >> 32), TWL_HIBQPH_REG_ADDR(tw_dev)); ++ /* Then the lower 4 bytes */ ++ writel((u32)(command_que_value | TWL_PULL_MODE), TWL_HIBQPL_REG_ADDR(tw_dev)); ++ ++ tw_dev->state[request_id] = TW_S_POSTED; ++ tw_dev->posted_request_count++; ++ if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) ++ tw_dev->max_posted_request_count = tw_dev->posted_request_count; ++ ++ return 0; ++} /* End twl_post_command_packet() */ ++ ++/* This function will perform a pci-dma mapping for a scatter gather list */ ++static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) ++{ ++ int use_sg; ++ struct scsi_cmnd *cmd = tw_dev->srb[request_id]; ++ ++ use_sg = scsi_dma_map(cmd); ++ if (!use_sg) ++ return 0; ++ else if (use_sg < 0) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list"); ++ return 0; ++ } ++ ++ cmd->SCp.phase = TW_PHASE_SGLIST; ++ cmd->SCp.have_data_in = use_sg; ++ ++ return use_sg; ++} /* End twl_map_scsi_sg_data() */ ++ ++/* This function hands scsi cdb's to the firmware */ ++static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg) ++{ ++ TW_Command_Full *full_command_packet; ++ TW_Command_Apache *command_packet; ++ int i, sg_count; ++ struct scsi_cmnd *srb = NULL; ++ struct scatterlist *sglist = NULL, *sg; ++ int retval = 1; ++ ++ if (tw_dev->srb[request_id]) { ++ srb = tw_dev->srb[request_id]; ++ if (scsi_sglist(srb)) ++ sglist = scsi_sglist(srb); ++ } ++ ++ /* Initialize command packet */ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ full_command_packet->header.header_desc.size_header = 128; ++ full_command_packet->header.status_block.error = 0; ++ full_command_packet->header.status_block.severity__reserved = 0; ++ ++ command_packet = &full_command_packet->command.newcommand; ++ command_packet->status = 0; ++ command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI); ++ ++ /* We forced 16 byte cdb use earlier */ ++ if (!cdb) ++ memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); ++ else ++ memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); ++ ++ if (srb) { ++ command_packet->unit = srb->device->id; ++ command_packet->request_id__lunl = ++ cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); ++ } else { ++ command_packet->request_id__lunl = ++ cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); ++ command_packet->unit = 0; ++ } ++ ++ command_packet->sgl_offset = 16; ++ ++ if (!sglistarg) { ++ /* Map sglist from scsi layer to cmd packet */ ++ if (scsi_sg_count(srb)) { ++ sg_count = twl_map_scsi_sg_data(tw_dev, request_id); ++ if (sg_count == 0) ++ goto out; ++ ++ scsi_for_each_sg(srb, sg, sg_count, i) { ++ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg)); ++ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sg_dma_len(sg)); ++ } ++ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); ++ } ++ } else { ++ /* Internal cdb post */ ++ for (i = 0; i < use_sg; i++) { ++ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); ++ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sglistarg[i].length); ++ } ++ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); ++ } ++ ++ /* Update some stats */ ++ if (srb) { ++ tw_dev->sector_count = scsi_bufflen(srb) / 512; ++ if (tw_dev->sector_count > tw_dev->max_sector_count) ++ tw_dev->max_sector_count = tw_dev->sector_count; ++ tw_dev->sgl_entries = scsi_sg_count(srb); ++ if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) ++ tw_dev->max_sgl_entries = tw_dev->sgl_entries; ++ } ++ ++ /* Now post the command to the board */ ++ retval = twl_post_command_packet(tw_dev, request_id); ++ ++out: ++ return retval; ++} /* End twl_scsiop_execute_scsi() */ ++ ++/* This function will read the aen queue from the isr */ ++static int twl_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) ++{ ++ char cdb[TW_MAX_CDB_LEN]; ++ TW_SG_Entry_ISO sglist[1]; ++ TW_Command_Full *full_command_packet; ++ int retval = 1; ++ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ memset(full_command_packet, 0, sizeof(TW_Command_Full)); ++ ++ /* Initialize cdb */ ++ memset(&cdb, 0, TW_MAX_CDB_LEN); ++ cdb[0] = REQUEST_SENSE; /* opcode */ ++ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ ++ ++ /* Initialize sglist */ ++ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO)); ++ sglist[0].length = TW_SECTOR_SIZE; ++ sglist[0].address = tw_dev->generic_buffer_phys[request_id]; ++ ++ /* Mark internal command */ ++ tw_dev->srb[request_id] = NULL; ++ ++ /* Now post the command packet */ ++ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Post failed while reading AEN queue"); ++ goto out; ++ } ++ retval = 0; ++out: ++ return retval; ++} /* End twl_aen_read_queue() */ ++ ++/* This function will sync firmware time with the host time */ ++static void twl_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) ++{ ++ u32 schedulertime; ++ struct timeval utc; ++ TW_Command_Full *full_command_packet; ++ TW_Command *command_packet; ++ TW_Param_Apache *param; ++ u32 local_time; ++ ++ /* Fill out the command packet */ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ memset(full_command_packet, 0, sizeof(TW_Command_Full)); ++ command_packet = &full_command_packet->command.oldcommand; ++ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); ++ command_packet->request_id = request_id; ++ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); ++ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE); ++ command_packet->size = TW_COMMAND_SIZE; ++ command_packet->byte6_offset.parameter_count = cpu_to_le16(1); ++ ++ /* Setup the param */ ++ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; ++ memset(param, 0, TW_SECTOR_SIZE); ++ param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */ ++ param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */ ++ param->parameter_size_bytes = cpu_to_le16(4); ++ ++ /* Convert system time in UTC to local time seconds since last ++ Sunday 12:00AM */ ++ do_gettimeofday(&utc); ++ local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); ++ schedulertime = local_time - (3 * 86400); ++ schedulertime = cpu_to_le32(schedulertime % 604800); ++ ++ memcpy(param->data, &schedulertime, sizeof(u32)); ++ ++ /* Mark internal command */ ++ tw_dev->srb[request_id] = NULL; ++ ++ /* Now post the command */ ++ twl_post_command_packet(tw_dev, request_id); ++} /* End twl_aen_sync_time() */ ++ ++/* This function will assign an available request id */ ++static void twl_get_request_id(TW_Device_Extension *tw_dev, int *request_id) ++{ ++ *request_id = tw_dev->free_queue[tw_dev->free_head]; ++ tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; ++ tw_dev->state[*request_id] = TW_S_STARTED; ++} /* End twl_get_request_id() */ ++ ++/* This function will free a request id */ ++static void twl_free_request_id(TW_Device_Extension *tw_dev, int request_id) ++{ ++ tw_dev->free_queue[tw_dev->free_tail] = request_id; ++ tw_dev->state[request_id] = TW_S_FINISHED; ++ tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; ++} /* End twl_free_request_id() */ ++ ++/* This function will complete an aen request from the isr */ ++static int twl_aen_complete(TW_Device_Extension *tw_dev, int request_id) ++{ ++ TW_Command_Full *full_command_packet; ++ TW_Command *command_packet; ++ TW_Command_Apache_Header *header; ++ unsigned short aen; ++ int retval = 1; ++ ++ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; ++ tw_dev->posted_request_count--; ++ aen = le16_to_cpu(header->status_block.error); ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ command_packet = &full_command_packet->command.oldcommand; ++ ++ /* First check for internal completion of set param for time sync */ ++ if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) { ++ /* Keep reading the queue in case there are more aen's */ ++ if (twl_aen_read_queue(tw_dev, request_id)) ++ goto out2; ++ else { ++ retval = 0; ++ goto out; ++ } ++ } ++ ++ switch (aen) { ++ case TW_AEN_QUEUE_EMPTY: ++ /* Quit reading the queue if this is the last one */ ++ break; ++ case TW_AEN_SYNC_TIME_WITH_HOST: ++ twl_aen_sync_time(tw_dev, request_id); ++ retval = 0; ++ goto out; ++ default: ++ twl_aen_queue_event(tw_dev, header); ++ ++ /* If there are more aen's, keep reading the queue */ ++ if (twl_aen_read_queue(tw_dev, request_id)) ++ goto out2; ++ else { ++ retval = 0; ++ goto out; ++ } ++ } ++ retval = 0; ++out2: ++ tw_dev->state[request_id] = TW_S_COMPLETED; ++ twl_free_request_id(tw_dev, request_id); ++ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); ++out: ++ return retval; ++} /* End twl_aen_complete() */ ++ ++/* This function will poll for a response */ ++static int twl_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) ++{ ++ unsigned long before; ++ dma_addr_t mfa; ++ u32 regh, regl; ++ u32 response; ++ int retval = 1; ++ int found = 0; ++ ++ before = jiffies; ++ ++ while (!found) { ++ if (sizeof(dma_addr_t) > 4) { ++ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev)); ++ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); ++ mfa = ((u64)regh << 32) | regl; ++ } else ++ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); ++ ++ response = (u32)mfa; ++ ++ if (TW_RESID_OUT(response) == request_id) ++ found = 1; ++ ++ if (time_after(jiffies, before + HZ * seconds)) ++ goto out; ++ ++ msleep(50); ++ } ++ retval = 0; ++out: ++ return retval; ++} /* End twl_poll_response() */ ++ ++/* This function will drain the aen queue */ ++static int twl_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) ++{ ++ int request_id = 0; ++ char cdb[TW_MAX_CDB_LEN]; ++ TW_SG_Entry_ISO sglist[1]; ++ int finished = 0, count = 0; ++ TW_Command_Full *full_command_packet; ++ TW_Command_Apache_Header *header; ++ unsigned short aen; ++ int first_reset = 0, queue = 0, retval = 1; ++ ++ if (no_check_reset) ++ first_reset = 0; ++ else ++ first_reset = 1; ++ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ memset(full_command_packet, 0, sizeof(TW_Command_Full)); ++ ++ /* Initialize cdb */ ++ memset(&cdb, 0, TW_MAX_CDB_LEN); ++ cdb[0] = REQUEST_SENSE; /* opcode */ ++ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ ++ ++ /* Initialize sglist */ ++ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO)); ++ sglist[0].length = TW_SECTOR_SIZE; ++ sglist[0].address = tw_dev->generic_buffer_phys[request_id]; ++ ++ /* Mark internal command */ ++ tw_dev->srb[request_id] = NULL; ++ ++ do { ++ /* Send command to the board */ ++ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "Error posting request sense"); ++ goto out; ++ } ++ ++ /* Now poll for completion */ ++ if (twl_poll_response(tw_dev, request_id, 30)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "No valid response while draining AEN queue"); ++ tw_dev->posted_request_count--; ++ goto out; ++ } ++ ++ tw_dev->posted_request_count--; ++ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; ++ aen = le16_to_cpu(header->status_block.error); ++ queue = 0; ++ count++; ++ ++ switch (aen) { ++ case TW_AEN_QUEUE_EMPTY: ++ if (first_reset != 1) ++ goto out; ++ else ++ finished = 1; ++ break; ++ case TW_AEN_SOFT_RESET: ++ if (first_reset == 0) ++ first_reset = 1; ++ else ++ queue = 1; ++ break; ++ case TW_AEN_SYNC_TIME_WITH_HOST: ++ break; ++ default: ++ queue = 1; ++ } ++ ++ /* Now queue an event info */ ++ if (queue) ++ twl_aen_queue_event(tw_dev, header); ++ } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN)); ++ ++ if (count == TW_MAX_AEN_DRAIN) ++ goto out; ++ ++ retval = 0; ++out: ++ tw_dev->state[request_id] = TW_S_INITIAL; ++ return retval; ++} /* End twl_aen_drain_queue() */ ++ ++/* This function will allocate memory and check if it is correctly aligned */ ++static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) ++{ ++ int i; ++ dma_addr_t dma_handle; ++ unsigned long *cpu_addr; ++ int retval = 1; ++ ++ cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); ++ if (!cpu_addr) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); ++ goto out; ++ } ++ ++ memset(cpu_addr, 0, size*TW_Q_LENGTH); ++ ++ for (i = 0; i < TW_Q_LENGTH; i++) { ++ switch(which) { ++ case 0: ++ tw_dev->command_packet_phys[i] = dma_handle+(i*size); ++ tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size)); ++ break; ++ case 1: ++ tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); ++ tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); ++ break; ++ case 2: ++ tw_dev->sense_buffer_phys[i] = dma_handle+(i*size); ++ tw_dev->sense_buffer_virt[i] = (TW_Command_Apache_Header *)((unsigned char *)cpu_addr + (i*size)); ++ break; ++ } ++ } ++ retval = 0; ++out: ++ return retval; ++} /* End twl_allocate_memory() */ ++ ++/* This function will load the request id and various sgls for ioctls */ ++static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) ++{ ++ TW_Command *oldcommand; ++ TW_Command_Apache *newcommand; ++ TW_SG_Entry_ISO *sgl; ++ unsigned int pae = 0; ++ ++ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) ++ pae = 1; ++ ++ if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { ++ newcommand = &full_command_packet->command.newcommand; ++ newcommand->request_id__lunl = ++ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); ++ if (length) { ++ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); ++ newcommand->sg_list[0].length = TW_CPU_TO_SGL(length); ++ } ++ newcommand->sgl_entries__lunh = ++ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); ++ } else { ++ oldcommand = &full_command_packet->command.oldcommand; ++ oldcommand->request_id = request_id; ++ ++ if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { ++ /* Load the sg list */ ++ sgl = (TW_SG_Entry_ISO *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry_ISO)/4) + pae + (sizeof(dma_addr_t) > 4 ? 1 : 0)); ++ sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); ++ sgl->length = TW_CPU_TO_SGL(length); ++ oldcommand->size += pae; ++ oldcommand->size += sizeof(dma_addr_t) > 4 ? 1 : 0; ++ } ++ } ++} /* End twl_load_sgl() */ ++ ++/* This function handles ioctl for the character device ++ This interface is used by smartmontools open source software */ ++static int twl_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long timeout; ++ unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; ++ dma_addr_t dma_handle; ++ int request_id = 0; ++ TW_Ioctl_Driver_Command driver_command; ++ TW_Ioctl_Buf_Apache *tw_ioctl; ++ TW_Command_Full *full_command_packet; ++ TW_Device_Extension *tw_dev = twl_device_extension_list[iminor(inode)]; ++ int retval = -EFAULT; ++ void __user *argp = (void __user *)arg; ++ ++ /* Only let one of these through at a time */ ++ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { ++ retval = -EINTR; ++ goto out; ++ } ++ ++ /* First copy down the driver command */ ++ if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command))) ++ goto out2; ++ ++ /* Check data buffer size */ ++ if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) { ++ retval = -EINVAL; ++ goto out2; ++ } ++ ++ /* Hardware can only do multiple of 512 byte transfers */ ++ data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; ++ ++ /* Now allocate ioctl buf memory */ ++ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL); ++ if (!cpu_addr) { ++ retval = -ENOMEM; ++ goto out2; ++ } ++ ++ tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; ++ ++ /* Now copy down the entire ioctl */ ++ if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) ++ goto out3; ++ ++ /* See which ioctl we are doing */ ++ switch (cmd) { ++ case TW_IOCTL_FIRMWARE_PASS_THROUGH: ++ spin_lock_irqsave(tw_dev->host->host_lock, flags); ++ twl_get_request_id(tw_dev, &request_id); ++ ++ /* Flag internal command */ ++ tw_dev->srb[request_id] = NULL; ++ ++ /* Flag chrdev ioctl */ ++ tw_dev->chrdev_request_id = request_id; ++ ++ full_command_packet = (TW_Command_Full *)&tw_ioctl->firmware_command; ++ ++ /* Load request id and sglist for both command types */ ++ twl_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); ++ ++ memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); ++ ++ /* Now post the command packet to the controller */ ++ twl_post_command_packet(tw_dev, request_id); ++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); ++ ++ timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; ++ ++ /* Now wait for command to complete */ ++ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); ++ ++ /* We timed out, and didn't get an interrupt */ ++ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { ++ /* Now we need to reset the board */ ++ printk(KERN_WARNING "3w-sas: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", ++ tw_dev->host->host_no, TW_DRIVER, 0x6, ++ cmd); ++ retval = -EIO; ++ twl_reset_device_extension(tw_dev, 1); ++ goto out3; ++ } ++ ++ /* Now copy in the command packet response */ ++ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); ++ ++ /* Now complete the io */ ++ spin_lock_irqsave(tw_dev->host->host_lock, flags); ++ tw_dev->posted_request_count--; ++ tw_dev->state[request_id] = TW_S_COMPLETED; ++ twl_free_request_id(tw_dev, request_id); ++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); ++ break; ++ default: ++ retval = -ENOTTY; ++ goto out3; ++ } ++ ++ /* Now copy the entire response to userspace */ ++ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) ++ retval = 0; ++out3: ++ /* Now free ioctl buf memory */ ++ dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); ++out2: ++ mutex_unlock(&tw_dev->ioctl_lock); ++out: ++ return retval; ++} /* End twl_chrdev_ioctl() */ ++ ++/* This function handles open for the character device */ ++static int twl_chrdev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor_number; ++ int retval = -ENODEV; ++ ++ if (!capable(CAP_SYS_ADMIN)) { ++ retval = -EACCES; ++ goto out; ++ } ++ ++ cycle_kernel_lock(); ++ minor_number = iminor(inode); ++ if (minor_number >= twl_device_extension_count) ++ goto out; ++ retval = 0; ++out: ++ return retval; ++} /* End twl_chrdev_open() */ ++ ++/* File operations struct for character device */ ++static const struct file_operations twl_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = twl_chrdev_ioctl, ++ .open = twl_chrdev_open, ++ .release = NULL ++}; ++ ++/* This function passes sense data from firmware to scsi layer */ ++static int twl_fill_sense(TW_Device_Extension *tw_dev, int i, int request_id, int copy_sense, int print_host) ++{ ++ TW_Command_Apache_Header *header; ++ TW_Command_Full *full_command_packet; ++ unsigned short error; ++ char *error_str; ++ int retval = 1; ++ ++ header = tw_dev->sense_buffer_virt[i]; ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ ++ /* Get embedded firmware error string */ ++ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc) + 1]); ++ ++ /* Don't print error for Logical unit not supported during rollcall */ ++ error = le16_to_cpu(header->status_block.error); ++ if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE) && (error != TW_ERROR_INVALID_FIELD_IN_CDB)) { ++ if (print_host) ++ printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", ++ tw_dev->host->host_no, ++ TW_MESSAGE_SOURCE_CONTROLLER_ERROR, ++ header->status_block.error, ++ error_str, ++ header->err_specific_desc); ++ else ++ printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s:%s.\n", ++ TW_MESSAGE_SOURCE_CONTROLLER_ERROR, ++ header->status_block.error, ++ error_str, ++ header->err_specific_desc); ++ } ++ ++ if (copy_sense) { ++ memcpy(tw_dev->srb[request_id]->sense_buffer, header->sense_data, TW_SENSE_DATA_LENGTH); ++ tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); ++ goto out; ++ } ++out: ++ return retval; ++} /* End twl_fill_sense() */ ++ ++/* This function will free up device extension resources */ ++static void twl_free_device_extension(TW_Device_Extension *tw_dev) ++{ ++ if (tw_dev->command_packet_virt[0]) ++ pci_free_consistent(tw_dev->tw_pci_dev, ++ sizeof(TW_Command_Full)*TW_Q_LENGTH, ++ tw_dev->command_packet_virt[0], ++ tw_dev->command_packet_phys[0]); ++ ++ if (tw_dev->generic_buffer_virt[0]) ++ pci_free_consistent(tw_dev->tw_pci_dev, ++ TW_SECTOR_SIZE*TW_Q_LENGTH, ++ tw_dev->generic_buffer_virt[0], ++ tw_dev->generic_buffer_phys[0]); ++ ++ if (tw_dev->sense_buffer_virt[0]) ++ pci_free_consistent(tw_dev->tw_pci_dev, ++ sizeof(TW_Command_Apache_Header)* ++ TW_Q_LENGTH, ++ tw_dev->sense_buffer_virt[0], ++ tw_dev->sense_buffer_phys[0]); ++ ++ kfree(tw_dev->event_queue[0]); ++} /* End twl_free_device_extension() */ ++ ++/* This function will get parameter table entries from the firmware */ ++static void *twl_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) ++{ ++ TW_Command_Full *full_command_packet; ++ TW_Command *command_packet; ++ TW_Param_Apache *param; ++ void *retval = NULL; ++ ++ /* Setup the command packet */ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ memset(full_command_packet, 0, sizeof(TW_Command_Full)); ++ command_packet = &full_command_packet->command.oldcommand; ++ ++ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); ++ command_packet->size = TW_COMMAND_SIZE; ++ command_packet->request_id = request_id; ++ command_packet->byte6_offset.block_count = cpu_to_le16(1); ++ ++ /* Now setup the param */ ++ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; ++ memset(param, 0, TW_SECTOR_SIZE); ++ param->table_id = cpu_to_le16(table_id | 0x8000); ++ param->parameter_id = cpu_to_le16(parameter_id); ++ param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); ++ ++ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); ++ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE); ++ ++ /* Post the command packet to the board */ ++ twl_post_command_packet(tw_dev, request_id); ++ ++ /* Poll for completion */ ++ if (twl_poll_response(tw_dev, request_id, 30)) ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "No valid response during get param") ++ else ++ retval = (void *)&(param->data[0]); ++ ++ tw_dev->posted_request_count--; ++ tw_dev->state[request_id] = TW_S_INITIAL; ++ ++ return retval; ++} /* End twl_get_param() */ ++ ++/* This function will send an initconnection command to controller */ ++static int twl_initconnection(TW_Device_Extension *tw_dev, int message_credits, ++ u32 set_features, unsigned short current_fw_srl, ++ unsigned short current_fw_arch_id, ++ unsigned short current_fw_branch, ++ unsigned short current_fw_build, ++ unsigned short *fw_on_ctlr_srl, ++ unsigned short *fw_on_ctlr_arch_id, ++ unsigned short *fw_on_ctlr_branch, ++ unsigned short *fw_on_ctlr_build, ++ u32 *init_connect_result) ++{ ++ TW_Command_Full *full_command_packet; ++ TW_Initconnect *tw_initconnect; ++ int request_id = 0, retval = 1; ++ ++ /* Initialize InitConnection command packet */ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ memset(full_command_packet, 0, sizeof(TW_Command_Full)); ++ full_command_packet->header.header_desc.size_header = 128; ++ ++ tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; ++ tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); ++ tw_initconnect->request_id = request_id; ++ tw_initconnect->message_credits = cpu_to_le16(message_credits); ++ tw_initconnect->features = set_features; ++ ++ /* Turn on 64-bit sgl support if we need to */ ++ tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; ++ ++ tw_initconnect->features = cpu_to_le32(tw_initconnect->features); ++ ++ if (set_features & TW_EXTENDED_INIT_CONNECT) { ++ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; ++ tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl); ++ tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id); ++ tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch); ++ tw_initconnect->fw_build = cpu_to_le16(current_fw_build); ++ } else ++ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; ++ ++ /* Send command packet to the board */ ++ twl_post_command_packet(tw_dev, request_id); ++ ++ /* Poll for completion */ ++ if (twl_poll_response(tw_dev, request_id, 30)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x8, "No valid response during init connection"); ++ } else { ++ if (set_features & TW_EXTENDED_INIT_CONNECT) { ++ *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl); ++ *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id); ++ *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch); ++ *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build); ++ *init_connect_result = le32_to_cpu(tw_initconnect->result); ++ } ++ retval = 0; ++ } ++ ++ tw_dev->posted_request_count--; ++ tw_dev->state[request_id] = TW_S_INITIAL; ++ ++ return retval; ++} /* End twl_initconnection() */ ++ ++/* This function will initialize the fields of a device extension */ ++static int twl_initialize_device_extension(TW_Device_Extension *tw_dev) ++{ ++ int i, retval = 1; ++ ++ /* Initialize command packet buffers */ ++ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x9, "Command packet memory allocation failed"); ++ goto out; ++ } ++ ++ /* Initialize generic buffer */ ++ if (twl_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Generic memory allocation failed"); ++ goto out; ++ } ++ ++ /* Allocate sense buffers */ ++ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Apache_Header), 2)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xb, "Sense buffer allocation failed"); ++ goto out; ++ } ++ ++ /* Allocate event info space */ ++ tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); ++ if (!tw_dev->event_queue[0]) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "Event info memory allocation failed"); ++ goto out; ++ } ++ ++ for (i = 0; i < TW_Q_LENGTH; i++) { ++ tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); ++ tw_dev->free_queue[i] = i; ++ tw_dev->state[i] = TW_S_INITIAL; ++ } ++ ++ tw_dev->free_head = TW_Q_START; ++ tw_dev->free_tail = TW_Q_START; ++ tw_dev->error_sequence_id = 1; ++ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; ++ ++ mutex_init(&tw_dev->ioctl_lock); ++ init_waitqueue_head(&tw_dev->ioctl_wqueue); ++ ++ retval = 0; ++out: ++ return retval; ++} /* End twl_initialize_device_extension() */ ++ ++/* This function will perform a pci-dma unmap */ ++static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) ++{ ++ struct scsi_cmnd *cmd = tw_dev->srb[request_id]; ++ ++ if (cmd->SCp.phase == TW_PHASE_SGLIST) ++ scsi_dma_unmap(cmd); ++} /* End twl_unmap_scsi_data() */ ++ ++/* This function will handle attention interrupts */ ++static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev) ++{ ++ int retval = 1; ++ u32 request_id, doorbell; ++ ++ /* Read doorbell status */ ++ doorbell = readl(TWL_HOBDB_REG_ADDR(tw_dev)); ++ ++ /* Check for controller errors */ ++ if (doorbell & TWL_DOORBELL_CONTROLLER_ERROR) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "Microcontroller Error: clearing"); ++ goto out; ++ } ++ ++ /* Check if we need to perform an AEN drain */ ++ if (doorbell & TWL_DOORBELL_ATTENTION_INTERRUPT) { ++ if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { ++ twl_get_request_id(tw_dev, &request_id); ++ if (twl_aen_read_queue(tw_dev, request_id)) { ++ tw_dev->state[request_id] = TW_S_COMPLETED; ++ twl_free_request_id(tw_dev, request_id); ++ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); ++ } ++ } ++ } ++ ++ retval = 0; ++out: ++ /* Clear doorbell interrupt */ ++ TWL_CLEAR_DB_INTERRUPT(tw_dev); ++ ++ /* Make sure the clear was flushed by reading it back */ ++ readl(TWL_HOBDBC_REG_ADDR(tw_dev)); ++ ++ return retval; ++} /* End twl_handle_attention_interrupt() */ ++ ++/* Interrupt service routine */ ++static irqreturn_t twl_interrupt(int irq, void *dev_instance) ++{ ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; ++ int i, handled = 0, error = 0; ++ dma_addr_t mfa = 0; ++ u32 reg, regl, regh, response, request_id = 0; ++ struct scsi_cmnd *cmd; ++ TW_Command_Full *full_command_packet; ++ ++ spin_lock(tw_dev->host->host_lock); ++ ++ /* Read host interrupt status */ ++ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev)); ++ ++ /* Check if this is our interrupt, otherwise bail */ ++ if (!(reg & TWL_HISTATUS_VALID_INTERRUPT)) ++ goto twl_interrupt_bail; ++ ++ handled = 1; ++ ++ /* If we are resetting, bail */ ++ if (test_bit(TW_IN_RESET, &tw_dev->flags)) ++ goto twl_interrupt_bail; ++ ++ /* Attention interrupt */ ++ if (reg & TWL_HISTATUS_ATTENTION_INTERRUPT) { ++ if (twl_handle_attention_interrupt(tw_dev)) { ++ TWL_MASK_INTERRUPTS(tw_dev); ++ goto twl_interrupt_bail; ++ } ++ } ++ ++ /* Response interrupt */ ++ while (reg & TWL_HISTATUS_RESPONSE_INTERRUPT) { ++ if (sizeof(dma_addr_t) > 4) { ++ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev)); ++ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); ++ mfa = ((u64)regh << 32) | regl; ++ } else ++ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); ++ ++ error = 0; ++ response = (u32)mfa; ++ ++ /* Check for command packet error */ ++ if (!TW_NOTMFA_OUT(response)) { ++ for (i=0;i<TW_Q_LENGTH;i++) { ++ if (tw_dev->sense_buffer_phys[i] == mfa) { ++ request_id = le16_to_cpu(tw_dev->sense_buffer_virt[i]->header_desc.request_id); ++ if (tw_dev->srb[request_id] != NULL) ++ error = twl_fill_sense(tw_dev, i, request_id, 1, 1); ++ else { ++ /* Skip ioctl error prints */ ++ if (request_id != tw_dev->chrdev_request_id) ++ error = twl_fill_sense(tw_dev, i, request_id, 0, 1); ++ else ++ memcpy(tw_dev->command_packet_virt[request_id], tw_dev->sense_buffer_virt[i], sizeof(TW_Command_Apache_Header)); ++ } ++ ++ /* Now re-post the sense buffer */ ++ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev)); ++ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev)); ++ break; ++ } ++ } ++ } else ++ request_id = TW_RESID_OUT(response); ++ ++ full_command_packet = tw_dev->command_packet_virt[request_id]; ++ ++ /* Check for correct state */ ++ if (tw_dev->state[request_id] != TW_S_POSTED) { ++ if (tw_dev->srb[request_id] != NULL) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Received a request id that wasn't posted"); ++ TWL_MASK_INTERRUPTS(tw_dev); ++ goto twl_interrupt_bail; ++ } ++ } ++ ++ /* Check for internal command completion */ ++ if (tw_dev->srb[request_id] == NULL) { ++ if (request_id != tw_dev->chrdev_request_id) { ++ if (twl_aen_complete(tw_dev, request_id)) ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "Error completing AEN during attention interrupt"); ++ } else { ++ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; ++ wake_up(&tw_dev->ioctl_wqueue); ++ } ++ } else { ++ cmd = tw_dev->srb[request_id]; ++ ++ if (!error) ++ cmd->result = (DID_OK << 16); ++ ++ /* Report residual bytes for single sgl */ ++ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { ++ if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) ++ scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); ++ } ++ ++ /* Now complete the io */ ++ tw_dev->state[request_id] = TW_S_COMPLETED; ++ twl_free_request_id(tw_dev, request_id); ++ tw_dev->posted_request_count--; ++ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); ++ twl_unmap_scsi_data(tw_dev, request_id); ++ } ++ ++ /* Check for another response interrupt */ ++ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev)); ++ } ++ ++twl_interrupt_bail: ++ spin_unlock(tw_dev->host->host_lock); ++ return IRQ_RETVAL(handled); ++} /* End twl_interrupt() */ ++ ++/* This function will poll for a register change */ ++static int twl_poll_register(TW_Device_Extension *tw_dev, void *reg, u32 value, u32 result, int seconds) ++{ ++ unsigned long before; ++ int retval = 1; ++ u32 reg_value; ++ ++ reg_value = readl(reg); ++ before = jiffies; ++ ++ while ((reg_value & value) != result) { ++ reg_value = readl(reg); ++ if (time_after(jiffies, before + HZ * seconds)) ++ goto out; ++ msleep(50); ++ } ++ retval = 0; ++out: ++ return retval; ++} /* End twl_poll_register() */ ++ ++/* This function will reset a controller */ ++static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) ++{ ++ int retval = 1; ++ int i = 0; ++ u32 status = 0; ++ unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; ++ unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; ++ u32 init_connect_result = 0; ++ int tries = 0; ++ int do_soft_reset = soft_reset; ++ ++ while (tries < TW_MAX_RESET_TRIES) { ++ /* Do a soft reset if one is needed */ ++ if (do_soft_reset) { ++ TWL_SOFT_RESET(tw_dev); ++ ++ /* Make sure controller is in a good state */ ++ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, 0x0, 30)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Controller never went non-ready during reset sequence"); ++ tries++; ++ continue; ++ } ++ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, TWL_CONTROLLER_READY, 60)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x11, "Controller not ready during reset sequence"); ++ tries++; ++ continue; ++ } ++ } ++ ++ /* Initconnect */ ++ if (twl_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, ++ TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL, ++ TW_9750_ARCH_ID, TW_CURRENT_DRIVER_BRANCH, ++ TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl, ++ &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, ++ &fw_on_ctlr_build, &init_connect_result)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x12, "Initconnection failed while checking SRL"); ++ do_soft_reset = 1; ++ tries++; ++ continue; ++ } ++ ++ /* Load sense buffers */ ++ while (i < TW_Q_LENGTH) { ++ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev)); ++ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev)); ++ ++ /* Check status for over-run after each write */ ++ status = readl(TWL_STATUS_REG_ADDR(tw_dev)); ++ if (!(status & TWL_STATUS_OVERRUN_SUBMIT)) ++ i++; ++ } ++ ++ /* Now check status */ ++ status = readl(TWL_STATUS_REG_ADDR(tw_dev)); ++ if (status) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "Bad controller status after loading sense buffers"); ++ do_soft_reset = 1; ++ tries++; ++ continue; ++ } ++ ++ /* Drain the AEN queue */ ++ if (twl_aen_drain_queue(tw_dev, soft_reset)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x14, "AEN drain failed during reset sequence"); ++ do_soft_reset = 1; ++ tries++; ++ continue; ++ } ++ ++ /* Load rest of compatibility struct */ ++ strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); ++ tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; ++ tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; ++ tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; ++ tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL; ++ tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH; ++ tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD; ++ tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl; ++ tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch; ++ tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build; ++ ++ /* If we got here, controller is in a good state */ ++ retval = 0; ++ goto out; ++ } ++out: ++ return retval; ++} /* End twl_reset_sequence() */ ++ ++/* This function will reset a device extension */ ++static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) ++{ ++ int i = 0, retval = 1; ++ unsigned long flags = 0; ++ ++ /* Block SCSI requests while we are resetting */ ++ if (ioctl_reset) ++ scsi_block_requests(tw_dev->host); ++ ++ set_bit(TW_IN_RESET, &tw_dev->flags); ++ TWL_MASK_INTERRUPTS(tw_dev); ++ TWL_CLEAR_DB_INTERRUPT(tw_dev); ++ ++ spin_lock_irqsave(tw_dev->host->host_lock, flags); ++ ++ /* Abort all requests that are in progress */ ++ for (i = 0; i < TW_Q_LENGTH; i++) { ++ if ((tw_dev->state[i] != TW_S_FINISHED) && ++ (tw_dev->state[i] != TW_S_INITIAL) && ++ (tw_dev->state[i] != TW_S_COMPLETED)) { ++ if (tw_dev->srb[i]) { ++ tw_dev->srb[i]->result = (DID_RESET << 16); ++ tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); ++ twl_unmap_scsi_data(tw_dev, i); ++ } ++ } ++ } ++ ++ /* Reset queues and counts */ ++ for (i = 0; i < TW_Q_LENGTH; i++) { ++ tw_dev->free_queue[i] = i; ++ tw_dev->state[i] = TW_S_INITIAL; ++ } ++ tw_dev->free_head = TW_Q_START; ++ tw_dev->free_tail = TW_Q_START; ++ tw_dev->posted_request_count = 0; ++ ++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); ++ ++ if (twl_reset_sequence(tw_dev, 1)) ++ goto out; ++ ++ TWL_UNMASK_INTERRUPTS(tw_dev); ++ ++ clear_bit(TW_IN_RESET, &tw_dev->flags); ++ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; ++ ++ retval = 0; ++out: ++ if (ioctl_reset) ++ scsi_unblock_requests(tw_dev->host); ++ return retval; ++} /* End twl_reset_device_extension() */ ++ ++/* This funciton returns unit geometry in cylinders/heads/sectors */ ++static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) ++{ ++ int heads, sectors, cylinders; ++ TW_Device_Extension *tw_dev; ++ ++ tw_dev = (TW_Device_Extension *)sdev->host->hostdata; ++ ++ if (capacity >= 0x200000) { ++ heads = 255; ++ sectors = 63; ++ cylinders = sector_div(capacity, heads * sectors); ++ } else { ++ heads = 64; ++ sectors = 32; ++ cylinders = sector_div(capacity, heads * sectors); ++ } ++ ++ geom[0] = heads; ++ geom[1] = sectors; ++ geom[2] = cylinders; ++ ++ return 0; ++} /* End twl_scsi_biosparam() */ ++ ++/* This is the new scsi eh reset function */ ++static int twl_scsi_eh_reset(struct scsi_cmnd *SCpnt) ++{ ++ TW_Device_Extension *tw_dev = NULL; ++ int retval = FAILED; ++ ++ tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; ++ ++ tw_dev->num_resets++; ++ ++ sdev_printk(KERN_WARNING, SCpnt->device, ++ "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n", ++ TW_DRIVER, 0x2c, SCpnt->cmnd[0]); ++ ++ /* Make sure we are not issuing an ioctl or resetting from ioctl */ ++ mutex_lock(&tw_dev->ioctl_lock); ++ ++ /* Now reset the card and some of the device extension data */ ++ if (twl_reset_device_extension(tw_dev, 0)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "Controller reset failed during scsi host reset"); ++ goto out; ++ } ++ ++ retval = SUCCESS; ++out: ++ mutex_unlock(&tw_dev->ioctl_lock); ++ return retval; ++} /* End twl_scsi_eh_reset() */ ++ ++/* This is the main scsi queue function to handle scsi opcodes */ ++static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) ++{ ++ int request_id, retval; ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; ++ ++ /* If we are resetting due to timed out ioctl, report as busy */ ++ if (test_bit(TW_IN_RESET, &tw_dev->flags)) { ++ retval = SCSI_MLQUEUE_HOST_BUSY; ++ goto out; ++ } ++ ++ /* Save done function into scsi_cmnd struct */ ++ SCpnt->scsi_done = done; ++ ++ /* Get a free request id */ ++ twl_get_request_id(tw_dev, &request_id); ++ ++ /* Save the scsi command for use by the ISR */ ++ tw_dev->srb[request_id] = SCpnt; ++ ++ /* Initialize phase to zero */ ++ SCpnt->SCp.phase = TW_PHASE_INITIAL; ++ ++ retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); ++ if (retval) { ++ tw_dev->state[request_id] = TW_S_COMPLETED; ++ twl_free_request_id(tw_dev, request_id); ++ SCpnt->result = (DID_ERROR << 16); ++ done(SCpnt); ++ retval = 0; ++ } ++out: ++ return retval; ++} /* End twl_scsi_queue() */ ++ ++/* This function tells the controller to shut down */ ++static void __twl_shutdown(TW_Device_Extension *tw_dev) ++{ ++ /* Disable interrupts */ ++ TWL_MASK_INTERRUPTS(tw_dev); ++ ++ /* Free up the IRQ */ ++ free_irq(tw_dev->tw_pci_dev->irq, tw_dev); ++ ++ printk(KERN_WARNING "3w-sas: Shutting down host %d.\n", tw_dev->host->host_no); ++ ++ /* Tell the card we are shutting down */ ++ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Connection shutdown failed"); ++ } else { ++ printk(KERN_WARNING "3w-sas: Shutdown complete.\n"); ++ } ++ ++ /* Clear doorbell interrupt just before exit */ ++ TWL_CLEAR_DB_INTERRUPT(tw_dev); ++} /* End __twl_shutdown() */ ++ ++/* Wrapper for __twl_shutdown */ ++static void twl_shutdown(struct pci_dev *pdev) ++{ ++ struct Scsi_Host *host = pci_get_drvdata(pdev); ++ TW_Device_Extension *tw_dev; ++ ++ if (!host) ++ return; ++ ++ tw_dev = (TW_Device_Extension *)host->hostdata; ++ ++ if (tw_dev->online) ++ __twl_shutdown(tw_dev); ++} /* End twl_shutdown() */ ++ ++/* This function configures unit settings when a unit is coming on-line */ ++static int twl_slave_configure(struct scsi_device *sdev) ++{ ++ /* Force 60 second timeout */ ++ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); ++ ++ return 0; ++} /* End twl_slave_configure() */ ++ ++/* scsi_host_template initializer */ ++static struct scsi_host_template driver_template = { ++ .module = THIS_MODULE, ++ .name = "3w-sas", ++ .queuecommand = twl_scsi_queue, ++ .eh_host_reset_handler = twl_scsi_eh_reset, ++ .bios_param = twl_scsi_biosparam, ++ .change_queue_depth = twl_change_queue_depth, ++ .can_queue = TW_Q_LENGTH-2, ++ .slave_configure = twl_slave_configure, ++ .this_id = -1, ++ .sg_tablesize = TW_LIBERATOR_MAX_SGL_LENGTH, ++ .max_sectors = TW_MAX_SECTORS, ++ .cmd_per_lun = TW_MAX_CMDS_PER_LUN, ++ .use_clustering = ENABLE_CLUSTERING, ++ .shost_attrs = twl_host_attrs, ++ .emulated = 1 ++}; ++ ++/* This function will probe and initialize a card */ ++static int __devinit twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) ++{ ++ struct Scsi_Host *host = NULL; ++ TW_Device_Extension *tw_dev; ++ resource_size_t mem_addr, mem_len; ++ int retval = -ENODEV; ++ int *ptr_phycount, phycount=0; ++ ++ retval = pci_enable_device(pdev); ++ if (retval) { ++ TW_PRINTK(host, TW_DRIVER, 0x17, "Failed to enable pci device"); ++ goto out_disable_device; ++ } ++ ++ pci_set_master(pdev); ++ pci_try_set_mwi(pdev); ++ ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) ++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { ++ TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask"); ++ retval = -ENODEV; ++ goto out_disable_device; ++ } ++ ++ host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); ++ if (!host) { ++ TW_PRINTK(host, TW_DRIVER, 0x19, "Failed to allocate memory for device extension"); ++ retval = -ENOMEM; ++ goto out_disable_device; ++ } ++ tw_dev = (TW_Device_Extension *)host->hostdata; ++ ++ /* Save values to device extension */ ++ tw_dev->host = host; ++ tw_dev->tw_pci_dev = pdev; ++ ++ if (twl_initialize_device_extension(tw_dev)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension"); ++ goto out_free_device_extension; ++ } ++ ++ /* Request IO regions */ ++ retval = pci_request_regions(pdev, "3w-sas"); ++ if (retval) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Failed to get mem region"); ++ goto out_free_device_extension; ++ } ++ ++ /* Use region 1 */ ++ mem_addr = pci_resource_start(pdev, 1); ++ mem_len = pci_resource_len(pdev, 1); ++ ++ /* Save base address */ ++ tw_dev->base_addr = ioremap(mem_addr, mem_len); ++ ++ if (!tw_dev->base_addr) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap"); ++ goto out_release_mem_region; ++ } ++ ++ /* Disable interrupts on the card */ ++ TWL_MASK_INTERRUPTS(tw_dev); ++ ++ /* Initialize the card */ ++ if (twl_reset_sequence(tw_dev, 0)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe"); ++ goto out_iounmap; ++ } ++ ++ /* Set host specific parameters */ ++ host->max_id = TW_MAX_UNITS; ++ host->max_cmd_len = TW_MAX_CDB_LEN; ++ host->max_lun = TW_MAX_LUNS; ++ host->max_channel = 0; ++ ++ /* Register the card with the kernel SCSI layer */ ++ retval = scsi_add_host(host, &pdev->dev); ++ if (retval) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "scsi add host failed"); ++ goto out_iounmap; ++ } ++ ++ pci_set_drvdata(pdev, host); ++ ++ printk(KERN_WARNING "3w-sas: scsi%d: Found an LSI 3ware %s Controller at 0x%llx, IRQ: %d.\n", ++ host->host_no, ++ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE, ++ TW_PARAM_MODEL, TW_PARAM_MODEL_LENGTH), ++ (u64)mem_addr, pdev->irq); ++ ++ ptr_phycount = twl_get_param(tw_dev, 2, TW_PARAM_PHY_SUMMARY_TABLE, ++ TW_PARAM_PHYCOUNT, TW_PARAM_PHYCOUNT_LENGTH); ++ if (ptr_phycount) ++ phycount = le32_to_cpu(*(int *)ptr_phycount); ++ ++ printk(KERN_WARNING "3w-sas: scsi%d: Firmware %s, BIOS %s, Phys: %d.\n", ++ host->host_no, ++ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE, ++ TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), ++ (char *)twl_get_param(tw_dev, 2, TW_VERSION_TABLE, ++ TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), ++ phycount); ++ ++ /* Try to enable MSI */ ++ if (use_msi && !pci_enable_msi(pdev)) ++ set_bit(TW_USING_MSI, &tw_dev->flags); ++ ++ /* Now setup the interrupt handler */ ++ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev); ++ if (retval) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Error requesting IRQ"); ++ goto out_remove_host; ++ } ++ ++ twl_device_extension_list[twl_device_extension_count] = tw_dev; ++ twl_device_extension_count++; ++ ++ /* Re-enable interrupts on the card */ ++ TWL_UNMASK_INTERRUPTS(tw_dev); ++ ++ /* Finally, scan the host */ ++ scsi_scan_host(host); ++ ++ /* Add sysfs binary files */ ++ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr)) ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Failed to create sysfs binary file: 3ware_aen_read"); ++ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr)) ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Failed to create sysfs binary file: 3ware_compat_info"); ++ ++ if (twl_major == -1) { ++ if ((twl_major = register_chrdev (0, "twl", &twl_fops)) < 0) ++ TW_PRINTK(host, TW_DRIVER, 0x22, "Failed to register character device"); ++ } ++ tw_dev->online = 1; ++ return 0; ++ ++out_remove_host: ++ if (test_bit(TW_USING_MSI, &tw_dev->flags)) ++ pci_disable_msi(pdev); ++ scsi_remove_host(host); ++out_iounmap: ++ iounmap(tw_dev->base_addr); ++out_release_mem_region: ++ pci_release_regions(pdev); ++out_free_device_extension: ++ twl_free_device_extension(tw_dev); ++ scsi_host_put(host); ++out_disable_device: ++ pci_disable_device(pdev); ++ ++ return retval; ++} /* End twl_probe() */ ++ ++/* This function is called to remove a device */ ++static void twl_remove(struct pci_dev *pdev) ++{ ++ struct Scsi_Host *host = pci_get_drvdata(pdev); ++ TW_Device_Extension *tw_dev; ++ ++ if (!host) ++ return; ++ ++ tw_dev = (TW_Device_Extension *)host->hostdata; ++ ++ if (!tw_dev->online) ++ return; ++ ++ /* Remove sysfs binary files */ ++ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr); ++ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr); ++ ++ scsi_remove_host(tw_dev->host); ++ ++ /* Unregister character device */ ++ if (twl_major >= 0) { ++ unregister_chrdev(twl_major, "twl"); ++ twl_major = -1; ++ } ++ ++ /* Shutdown the card */ ++ __twl_shutdown(tw_dev); ++ ++ /* Disable MSI if enabled */ ++ if (test_bit(TW_USING_MSI, &tw_dev->flags)) ++ pci_disable_msi(pdev); ++ ++ /* Free IO remapping */ ++ iounmap(tw_dev->base_addr); ++ ++ /* Free up the mem region */ ++ pci_release_regions(pdev); ++ ++ /* Free up device extension resources */ ++ twl_free_device_extension(tw_dev); ++ ++ scsi_host_put(tw_dev->host); ++ pci_disable_device(pdev); ++ twl_device_extension_count--; ++} /* End twl_remove() */ ++ ++#ifdef CONFIG_PM ++/* This function is called on PCI suspend */ ++static int twl_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct Scsi_Host *host = pci_get_drvdata(pdev); ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; ++ ++ printk(KERN_WARNING "3w-sas: Suspending host %d.\n", tw_dev->host->host_no); ++ /* Disable interrupts */ ++ TWL_MASK_INTERRUPTS(tw_dev); ++ ++ free_irq(tw_dev->tw_pci_dev->irq, tw_dev); ++ ++ /* Tell the card we are shutting down */ ++ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x23, "Connection shutdown failed during suspend"); ++ } else { ++ printk(KERN_WARNING "3w-sas: Suspend complete.\n"); ++ } ++ ++ /* Clear doorbell interrupt */ ++ TWL_CLEAR_DB_INTERRUPT(tw_dev); ++ ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ ++ return 0; ++} /* End twl_suspend() */ ++ ++/* This function is called on PCI resume */ ++static int twl_resume(struct pci_dev *pdev) ++{ ++ int retval = 0; ++ struct Scsi_Host *host = pci_get_drvdata(pdev); ++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; ++ ++ printk(KERN_WARNING "3w-sas: Resuming host %d.\n", tw_dev->host->host_no); ++ pci_set_power_state(pdev, PCI_D0); ++ pci_enable_wake(pdev, PCI_D0, 0); ++ pci_restore_state(pdev); ++ ++ retval = pci_enable_device(pdev); ++ if (retval) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x24, "Enable device failed during resume"); ++ return retval; ++ } ++ ++ pci_set_master(pdev); ++ pci_try_set_mwi(pdev); ++ ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) ++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { ++ TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume"); ++ retval = -ENODEV; ++ goto out_disable_device; ++ } ++ ++ /* Initialize the card */ ++ if (twl_reset_sequence(tw_dev, 0)) { ++ retval = -ENODEV; ++ goto out_disable_device; ++ } ++ ++ /* Now setup the interrupt handler */ ++ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev); ++ if (retval) { ++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Error requesting IRQ during resume"); ++ retval = -ENODEV; ++ goto out_disable_device; ++ } ++ ++ /* Now enable MSI if enabled */ ++ if (test_bit(TW_USING_MSI, &tw_dev->flags)) ++ pci_enable_msi(pdev); ++ ++ /* Re-enable interrupts on the card */ ++ TWL_UNMASK_INTERRUPTS(tw_dev); ++ ++ printk(KERN_WARNING "3w-sas: Resume complete.\n"); ++ return 0; ++ ++out_disable_device: ++ scsi_remove_host(host); ++ pci_disable_device(pdev); ++ ++ return retval; ++} /* End twl_resume() */ ++#endif ++ ++/* PCI Devices supported by this driver */ ++static struct pci_device_id twl_pci_tbl[] __devinitdata = { ++ { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9750, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(pci, twl_pci_tbl); ++ ++/* pci_driver initializer */ ++static struct pci_driver twl_driver = { ++ .name = "3w-sas", ++ .id_table = twl_pci_tbl, ++ .probe = twl_probe, ++ .remove = twl_remove, ++#ifdef CONFIG_PM ++ .suspend = twl_suspend, ++ .resume = twl_resume, ++#endif ++ .shutdown = twl_shutdown ++}; ++ ++/* This function is called on driver initialization */ ++static int __init twl_init(void) ++{ ++ printk(KERN_WARNING "LSI 3ware SAS/SATA-RAID Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); ++ ++ return pci_register_driver(&twl_driver); ++} /* End twl_init() */ ++ ++/* This function is called on driver exit */ ++static void __exit twl_exit(void) ++{ ++ pci_unregister_driver(&twl_driver); ++} /* End twl_exit() */ ++ ++module_init(twl_init); ++module_exit(twl_exit); ++ +diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h +new file mode 100644 +index 0000000..e620505 +--- /dev/null ++++ b/drivers/scsi/3w-sas.h +@@ -0,0 +1,396 @@ ++/* ++ 3w-sas.h -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. ++ ++ Written By: Adam Radford <linuxraid@lsi.com> ++ ++ Copyright (C) 2009 LSI 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; 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 ++ ++ Bugs/Comments/Suggestions should be mailed to: ++ linuxraid@lsi.com ++ ++ For more information, goto: ++ http://www.lsi.com ++*/ ++ ++#ifndef _3W_SAS_H ++#define _3W_SAS_H ++ ++/* AEN severity table */ ++static char *twl_aen_severity_table[] = ++{ ++ "None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0 ++}; ++ ++/* Liberator register offsets */ ++#define TWL_STATUS 0x0 /* Status */ ++#define TWL_HIBDB 0x20 /* Inbound doorbell */ ++#define TWL_HISTAT 0x30 /* Host interrupt status */ ++#define TWL_HIMASK 0x34 /* Host interrupt mask */ ++#define TWL_HOBDB 0x9C /* Outbound doorbell */ ++#define TWL_HOBDBC 0xA0 /* Outbound doorbell clear */ ++#define TWL_SCRPD3 0xBC /* Scratchpad */ ++#define TWL_HIBQPL 0xC0 /* Host inbound Q low */ ++#define TWL_HIBQPH 0xC4 /* Host inbound Q high */ ++#define TWL_HOBQPL 0xC8 /* Host outbound Q low */ ++#define TWL_HOBQPH 0xCC /* Host outbound Q high */ ++#define TWL_HISTATUS_VALID_INTERRUPT 0xC ++#define TWL_HISTATUS_ATTENTION_INTERRUPT 0x4 ++#define TWL_HISTATUS_RESPONSE_INTERRUPT 0x8 ++#define TWL_STATUS_OVERRUN_SUBMIT 0x2000 ++#define TWL_ISSUE_SOFT_RESET 0x100 ++#define TWL_CONTROLLER_READY 0x2000 ++#define TWL_DOORBELL_CONTROLLER_ERROR 0x200000 ++#define TWL_DOORBELL_ATTENTION_INTERRUPT 0x40000 ++#define TWL_PULL_MODE 0x1 ++ ++/* Command packet opcodes used by the driver */ ++#define TW_OP_INIT_CONNECTION 0x1 ++#define TW_OP_GET_PARAM 0x12 ++#define TW_OP_SET_PARAM 0x13 ++#define TW_OP_EXECUTE_SCSI 0x10 ++ ++/* Asynchronous Event Notification (AEN) codes used by the driver */ ++#define TW_AEN_QUEUE_EMPTY 0x0000 ++#define TW_AEN_SOFT_RESET 0x0001 ++#define TW_AEN_SYNC_TIME_WITH_HOST 0x031 ++#define TW_AEN_SEVERITY_ERROR 0x1 ++#define TW_AEN_SEVERITY_DEBUG 0x4 ++#define TW_AEN_NOT_RETRIEVED 0x1 ++ ++/* Command state defines */ ++#define TW_S_INITIAL 0x1 /* Initial state */ ++#define TW_S_STARTED 0x2 /* Id in use */ ++#define TW_S_POSTED 0x4 /* Posted to the controller */ ++#define TW_S_COMPLETED 0x8 /* Completed by isr */ ++#define TW_S_FINISHED 0x10 /* I/O completely done */ ++ ++/* Compatibility defines */ ++#define TW_9750_ARCH_ID 10 ++#define TW_CURRENT_DRIVER_SRL 40 ++#define TW_CURRENT_DRIVER_BUILD 0 ++#define TW_CURRENT_DRIVER_BRANCH 0 ++ ++/* Phase defines */ ++#define TW_PHASE_INITIAL 0 ++#define TW_PHASE_SGLIST 2 ++ ++/* Misc defines */ ++#define TW_SECTOR_SIZE 512 ++#define TW_MAX_UNITS 32 ++#define TW_INIT_MESSAGE_CREDITS 0x100 ++#define TW_INIT_COMMAND_PACKET_SIZE 0x3 ++#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 ++#define TW_EXTENDED_INIT_CONNECT 0x2 ++#define TW_BASE_FW_SRL 24 ++#define TW_BASE_FW_BRANCH 0 ++#define TW_BASE_FW_BUILD 1 ++#define TW_Q_LENGTH 256 ++#define TW_Q_START 0 ++#define TW_MAX_SLOT 32 ++#define TW_MAX_RESET_TRIES 2 ++#define TW_MAX_CMDS_PER_LUN 254 ++#define TW_MAX_AEN_DRAIN 255 ++#define TW_IN_RESET 2 ++#define TW_USING_MSI 3 ++#define TW_IN_ATTENTION_LOOP 4 ++#define TW_MAX_SECTORS 256 ++#define TW_MAX_CDB_LEN 16 ++#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ ++#define TW_IOCTL_CHRDEV_FREE -1 ++#define TW_COMMAND_OFFSET 128 /* 128 bytes */ ++#define TW_VERSION_TABLE 0x0402 ++#define TW_TIMEKEEP_TABLE 0x040A ++#define TW_INFORMATION_TABLE 0x0403 ++#define TW_PARAM_FWVER 3 ++#define TW_PARAM_FWVER_LENGTH 16 ++#define TW_PARAM_BIOSVER 4 ++#define TW_PARAM_BIOSVER_LENGTH 16 ++#define TW_PARAM_MODEL 8 ++#define TW_PARAM_MODEL_LENGTH 16 ++#define TW_PARAM_PHY_SUMMARY_TABLE 1 ++#define TW_PARAM_PHYCOUNT 2 ++#define TW_PARAM_PHYCOUNT_LENGTH 1 ++#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 // Used by smartmontools ++#define TW_ALLOCATION_LENGTH 128 ++#define TW_SENSE_DATA_LENGTH 18 ++#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a ++#define TW_ERROR_INVALID_FIELD_IN_CDB 0x10d ++#define TW_ERROR_UNIT_OFFLINE 0x128 ++#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3 ++#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4 ++#define TW_DRIVER 6 ++#ifndef PCI_DEVICE_ID_3WARE_9750 ++#define PCI_DEVICE_ID_3WARE_9750 0x1010 ++#endif ++ ++/* Bitmask macros to eliminate bitfields */ ++ ++/* opcode: 5, reserved: 3 */ ++#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f)) ++#define TW_OP_OUT(x) (x & 0x1f) ++ ++/* opcode: 5, sgloffset: 3 */ ++#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f)) ++#define TW_SGL_OUT(x) ((x >> 5) & 0x7) ++ ++/* severity: 3, reserved: 5 */ ++#define TW_SEV_OUT(x) (x & 0x7) ++ ++/* not_mfa: 1, reserved: 7, status: 8, request_id: 16 */ ++#define TW_RESID_OUT(x) ((x >> 16) & 0xffff) ++#define TW_NOTMFA_OUT(x) (x & 0x1) ++ ++/* request_id: 12, lun: 4 */ ++#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff)) ++#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf) ++ ++/* Register access macros */ ++#define TWL_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_STATUS) ++#define TWL_HOBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPL) ++#define TWL_HOBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPH) ++#define TWL_HOBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDB) ++#define TWL_HOBDBC_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDBC) ++#define TWL_HIMASK_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIMASK) ++#define TWL_HISTAT_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HISTAT) ++#define TWL_HIBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPH) ++#define TWL_HIBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPL) ++#define TWL_HIBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBDB) ++#define TWL_SCRPD3_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_SCRPD3) ++#define TWL_MASK_INTERRUPTS(x) (writel(~0, TWL_HIMASK_REG_ADDR(tw_dev))) ++#define TWL_UNMASK_INTERRUPTS(x) (writel(~TWL_HISTATUS_VALID_INTERRUPT, TWL_HIMASK_REG_ADDR(tw_dev))) ++#define TWL_CLEAR_DB_INTERRUPT(x) (writel(~0, TWL_HOBDBC_REG_ADDR(tw_dev))) ++#define TWL_SOFT_RESET(x) (writel(TWL_ISSUE_SOFT_RESET, TWL_HIBDB_REG_ADDR(tw_dev))) ++ ++/* Macros */ ++#define TW_PRINTK(h,a,b,c) { \ ++if (h) \ ++printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \ ++else \ ++printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \ ++} ++#define TW_MAX_LUNS 16 ++#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 6 : 4) ++#define TW_LIBERATOR_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 46 : 92) ++#define TW_LIBERATOR_MAX_SGL_LENGTH_OLD (sizeof(dma_addr_t) > 4 ? 47 : 94) ++#define TW_PADDING_LENGTH_LIBERATOR 136 ++#define TW_PADDING_LENGTH_LIBERATOR_OLD 132 ++#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x)) ++ ++#pragma pack(1) ++ ++/* SGL entry */ ++typedef struct TAG_TW_SG_Entry_ISO { ++ dma_addr_t address; ++ dma_addr_t length; ++} TW_SG_Entry_ISO; ++ ++/* Old Command Packet with ISO SGL */ ++typedef struct TW_Command { ++ unsigned char opcode__sgloffset; ++ unsigned char size; ++ unsigned char request_id; ++ unsigned char unit__hostid; ++ /* Second DWORD */ ++ unsigned char status; ++ unsigned char flags; ++ union { ++ unsigned short block_count; ++ unsigned short parameter_count; ++ } byte6_offset; ++ union { ++ struct { ++ u32 lba; ++ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD]; ++ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR_OLD]; ++ } io; ++ struct { ++ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD]; ++ u32 padding; ++ unsigned char padding2[TW_PADDING_LENGTH_LIBERATOR_OLD]; ++ } param; ++ } byte8_offset; ++} TW_Command; ++ ++/* New Command Packet with ISO SGL */ ++typedef struct TAG_TW_Command_Apache { ++ unsigned char opcode__reserved; ++ unsigned char unit; ++ unsigned short request_id__lunl; ++ unsigned char status; ++ unsigned char sgl_offset; ++ unsigned short sgl_entries__lunh; ++ unsigned char cdb[16]; ++ TW_SG_Entry_ISO sg_list[TW_LIBERATOR_MAX_SGL_LENGTH]; ++ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR]; ++} TW_Command_Apache; ++ ++/* New command packet header */ ++typedef struct TAG_TW_Command_Apache_Header { ++ unsigned char sense_data[TW_SENSE_DATA_LENGTH]; ++ struct { ++ char reserved[4]; ++ unsigned short error; ++ unsigned char padding; ++ unsigned char severity__reserved; ++ } status_block; ++ unsigned char err_specific_desc[98]; ++ struct { ++ unsigned char size_header; ++ unsigned short request_id; ++ unsigned char size_sense; ++ } header_desc; ++} TW_Command_Apache_Header; ++ ++/* This struct is a union of the 2 command packets */ ++typedef struct TAG_TW_Command_Full { ++ TW_Command_Apache_Header header; ++ union { ++ TW_Command oldcommand; ++ TW_Command_Apache newcommand; ++ } command; ++} TW_Command_Full; ++ ++/* Initconnection structure */ ++typedef struct TAG_TW_Initconnect { ++ unsigned char opcode__reserved; ++ unsigned char size; ++ unsigned char request_id; ++ unsigned char res2; ++ unsigned char status; ++ unsigned char flags; ++ unsigned short message_credits; ++ u32 features; ++ unsigned short fw_srl; ++ unsigned short fw_arch_id; ++ unsigned short fw_branch; ++ unsigned short fw_build; ++ u32 result; ++} TW_Initconnect; ++ ++/* Event info structure */ ++typedef struct TAG_TW_Event ++{ ++ unsigned int sequence_id; ++ unsigned int time_stamp_sec; ++ unsigned short aen_code; ++ unsigned char severity; ++ unsigned char retrieved; ++ unsigned char repeat_count; ++ unsigned char parameter_len; ++ unsigned char parameter_data[98]; ++} TW_Event; ++ ++typedef struct TAG_TW_Ioctl_Driver_Command { ++ unsigned int control_code; ++ unsigned int status; ++ unsigned int unique_id; ++ unsigned int sequence_id; ++ unsigned int os_specific; ++ unsigned int buffer_length; ++} TW_Ioctl_Driver_Command; ++ ++typedef struct TAG_TW_Ioctl_Apache { ++ TW_Ioctl_Driver_Command driver_command; ++ char padding[488]; ++ TW_Command_Full firmware_command; ++ char data_buffer[1]; ++} TW_Ioctl_Buf_Apache; ++ ++/* GetParam descriptor */ ++typedef struct { ++ unsigned short table_id; ++ unsigned short parameter_id; ++ unsigned short parameter_size_bytes; ++ unsigned short actual_parameter_size_bytes; ++ unsigned char data[1]; ++} TW_Param_Apache; ++ ++/* Compatibility information structure */ ++typedef struct TAG_TW_Compatibility_Info ++{ ++ char driver_version[32]; ++ unsigned short working_srl; ++ unsigned short working_branch; ++ unsigned short working_build; ++ unsigned short driver_srl_high; ++ unsigned short driver_branch_high; ++ unsigned short driver_build_high; ++ unsigned short driver_srl_low; ++ unsigned short driver_branch_low; ++ unsigned short driver_build_low; ++ unsigned short fw_on_ctlr_srl; ++ unsigned short fw_on_ctlr_branch; ++ unsigned short fw_on_ctlr_build; ++} TW_Compatibility_Info; ++ ++#pragma pack() ++ ++typedef struct TAG_TW_Device_Extension { ++ void __iomem *base_addr; ++ unsigned long *generic_buffer_virt[TW_Q_LENGTH]; ++ dma_addr_t generic_buffer_phys[TW_Q_LENGTH]; ++ TW_Command_Full *command_packet_virt[TW_Q_LENGTH]; ++ dma_addr_t command_packet_phys[TW_Q_LENGTH]; ++ TW_Command_Apache_Header *sense_buffer_virt[TW_Q_LENGTH]; ++ dma_addr_t sense_buffer_phys[TW_Q_LENGTH]; ++ struct pci_dev *tw_pci_dev; ++ struct scsi_cmnd *srb[TW_Q_LENGTH]; ++ unsigned char free_queue[TW_Q_LENGTH]; ++ unsigned char free_head; ++ unsigned char free_tail; ++ int state[TW_Q_LENGTH]; ++ unsigned int posted_request_count; ++ unsigned int max_posted_request_count; ++ unsigned int max_sgl_entries; ++ unsigned int sgl_entries; ++ unsigned int num_resets; ++ unsigned int sector_count; ++ unsigned int max_sector_count; ++ unsigned int aen_count; ++ struct Scsi_Host *host; ++ long flags; ++ TW_Event *event_queue[TW_Q_LENGTH]; ++ unsigned char error_index; ++ unsigned int error_sequence_id; ++ int chrdev_request_id; ++ wait_queue_head_t ioctl_wqueue; ++ struct mutex ioctl_lock; ++ TW_Compatibility_Info tw_compat_info; ++ char online; ++} TW_Device_Extension; ++ ++#endif /* _3W_SAS_H */ ++ diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 1ddcf40..a85f062 100644 --- a/drivers/scsi/BusLogic.c @@ -40865,6 +56739,63 @@ index 1ddcf40..a85f062 100644 /* If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint Host Adapters; otherwise, default to the standard ISA MultiMaster probe. +diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig +index e11cca4..4295679 100644 +--- a/drivers/scsi/Kconfig ++++ b/drivers/scsi/Kconfig +@@ -399,6 +399,17 @@ config SCSI_3W_9XXX + Please read the comments at the top of + <file:drivers/scsi/3w-9xxx.c>. + ++config SCSI_3W_SAS ++ tristate "3ware 97xx SAS/SATA-RAID support" ++ depends on PCI && SCSI ++ help ++ This driver supports the LSI 3ware 9750 6Gb/s SAS/SATA-RAID cards. ++ ++ <http://www.lsi.com> ++ ++ Please read the comments at the top of ++ <file:drivers/scsi/3w-sas.c>. ++ + config SCSI_7000FASST + tristate "7000FASST SCSI support" + depends on ISA && SCSI && ISA_DMA_API +@@ -621,6 +632,14 @@ config SCSI_FLASHPOINT + substantial, so users of MultiMaster Host Adapters may not + wish to include it. + ++config VMWARE_PVSCSI ++ tristate "VMware PVSCSI driver support" ++ depends on PCI && SCSI && X86 ++ help ++ This driver supports VMware's para virtualized SCSI HBA. ++ To compile this driver as a module, choose M here: the ++ module will be called vmw_pvscsi. ++ + config LIBFC + tristate "LibFC module" + select SCSI_FC_ATTRS +diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile +index 3ad61db..c938975 100644 +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -113,6 +113,7 @@ obj-$(CONFIG_SCSI_MESH) += mesh.o + obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o + obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o + obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o ++obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o + obj-$(CONFIG_SCSI_PPA) += ppa.o + obj-$(CONFIG_SCSI_IMM) += imm.o + obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o +@@ -133,6 +134,7 @@ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/ + obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ + obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/ + obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o ++obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o + + obj-$(CONFIG_ARM) += arm/ + diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index cdbdec9..b7d560b 100644 --- a/drivers/scsi/aacraid/aacraid.h @@ -41854,6 +57785,1816 @@ index c19ca5e..3eb5959 100644 memset(&sym_dev, 0, sizeof(sym_dev)); memset(&nvram, 0, sizeof(nvram)); sym_dev.pdev = pdev; +diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c +new file mode 100644 +index 0000000..eabb432 +--- /dev/null ++++ b/drivers/scsi/vmw_pvscsi.c +@@ -0,0 +1,1401 @@ ++/* ++ * Linux driver for VMware's para-virtualized SCSI HBA. ++ * ++ * Copyright (C) 2008-2009, VMware, 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; version 2 of the License and no 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. ++ * ++ * Maintained by: Alok N Kataria <akataria@vmware.com> ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/types.h> ++#include <linux/interrupt.h> ++#include <linux/workqueue.h> ++#include <linux/pci.h> ++ ++#include <scsi/scsi.h> ++#include <scsi/scsi_host.h> ++#include <scsi/scsi_cmnd.h> ++#include <scsi/scsi_device.h> ++ ++#include "vmw_pvscsi.h" ++ ++#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver" ++ ++MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC); ++MODULE_AUTHOR("VMware, Inc."); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING); ++ ++#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 ++#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 ++#define PVSCSI_DEFAULT_QUEUE_DEPTH 64 ++#define SGL_SIZE PAGE_SIZE ++ ++#define pvscsi_dev(adapter) (&(adapter->dev->dev)) ++ ++struct pvscsi_sg_list { ++ struct PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT]; ++}; ++ ++struct pvscsi_ctx { ++ /* ++ * The index of the context in cmd_map serves as the context ID for a ++ * 1-to-1 mapping completions back to requests. ++ */ ++ struct scsi_cmnd *cmd; ++ struct pvscsi_sg_list *sgl; ++ struct list_head list; ++ dma_addr_t dataPA; ++ dma_addr_t sensePA; ++ dma_addr_t sglPA; ++}; ++ ++struct pvscsi_adapter { ++ char *mmioBase; ++ unsigned int irq; ++ u8 rev; ++ bool use_msi; ++ bool use_msix; ++ bool use_msg; ++ ++ spinlock_t hw_lock; ++ ++ struct workqueue_struct *workqueue; ++ struct work_struct work; ++ ++ struct PVSCSIRingReqDesc *req_ring; ++ unsigned req_pages; ++ unsigned req_depth; ++ dma_addr_t reqRingPA; ++ ++ struct PVSCSIRingCmpDesc *cmp_ring; ++ unsigned cmp_pages; ++ dma_addr_t cmpRingPA; ++ ++ struct PVSCSIRingMsgDesc *msg_ring; ++ unsigned msg_pages; ++ dma_addr_t msgRingPA; ++ ++ struct PVSCSIRingsState *rings_state; ++ dma_addr_t ringStatePA; ++ ++ struct pci_dev *dev; ++ struct Scsi_Host *host; ++ ++ struct list_head cmd_pool; ++ struct pvscsi_ctx *cmd_map; ++}; ++ ++ ++/* Command line parameters */ ++static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING; ++static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; ++static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH; ++static bool pvscsi_disable_msi; ++static bool pvscsi_disable_msix; ++static bool pvscsi_use_msg = true; ++ ++#define PVSCSI_RW (S_IRUSR | S_IWUSR) ++ ++module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW); ++MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default=" ++ __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")"); ++ ++module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW); ++MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default=" ++ __stringify(PVSCSI_DEFAULT_NUM_PAGES_MSG_RING) ")"); ++ ++module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW); ++MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default=" ++ __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")"); ++ ++module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW); ++MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); ++ ++module_param_named(disable_msix, pvscsi_disable_msix, bool, PVSCSI_RW); ++MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)"); ++ ++module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW); ++MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)"); ++ ++static const struct pci_device_id pvscsi_pci_tbl[] = { ++ { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) }, ++ { 0 } ++}; ++ ++MODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl); ++ ++static struct pvscsi_ctx * ++pvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) ++{ ++ struct pvscsi_ctx *ctx, *end; ++ ++ end = &adapter->cmd_map[adapter->req_depth]; ++ for (ctx = adapter->cmd_map; ctx < end; ctx++) ++ if (ctx->cmd == cmd) ++ return ctx; ++ ++ return NULL; ++} ++ ++static struct pvscsi_ctx * ++pvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) ++{ ++ struct pvscsi_ctx *ctx; ++ ++ if (list_empty(&adapter->cmd_pool)) ++ return NULL; ++ ++ ctx = list_first_entry(&adapter->cmd_pool, struct pvscsi_ctx, list); ++ ctx->cmd = cmd; ++ list_del(&ctx->list); ++ ++ return ctx; ++} ++ ++static void pvscsi_release_context(struct pvscsi_adapter *adapter, ++ struct pvscsi_ctx *ctx) ++{ ++ ctx->cmd = NULL; ++ list_add(&ctx->list, &adapter->cmd_pool); ++} ++ ++/* ++ * Map a pvscsi_ctx struct to a context ID field value; we map to a simple ++ * non-zero integer. ctx always points to an entry in cmd_map array, hence ++ * the return value is always >=1. ++ */ ++static u64 pvscsi_map_context(const struct pvscsi_adapter *adapter, ++ const struct pvscsi_ctx *ctx) ++{ ++ return ctx - adapter->cmd_map + 1; ++} ++ ++static struct pvscsi_ctx * ++pvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context) ++{ ++ return &adapter->cmd_map[context - 1]; ++} ++ ++static void pvscsi_reg_write(const struct pvscsi_adapter *adapter, ++ u32 offset, u32 val) ++{ ++ writel(val, adapter->mmioBase + offset); ++} ++ ++static u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter, u32 offset) ++{ ++ return readl(adapter->mmioBase + offset); ++} ++ ++static u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter) ++{ ++ return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS); ++} ++ ++static void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter, ++ u32 val) ++{ ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val); ++} ++ ++static void pvscsi_unmask_intr(const struct pvscsi_adapter *adapter) ++{ ++ u32 intr_bits; ++ ++ intr_bits = PVSCSI_INTR_CMPL_MASK; ++ if (adapter->use_msg) ++ intr_bits |= PVSCSI_INTR_MSG_MASK; ++ ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, intr_bits); ++} ++ ++static void pvscsi_mask_intr(const struct pvscsi_adapter *adapter) ++{ ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, 0); ++} ++ ++static void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter, ++ u32 cmd, const void *desc, size_t len) ++{ ++ const u32 *ptr = desc; ++ size_t i; ++ ++ len /= sizeof(*ptr); ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd); ++ for (i = 0; i < len; i++) ++ pvscsi_reg_write(adapter, ++ PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]); ++} ++ ++static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter, ++ const struct pvscsi_ctx *ctx) ++{ ++ struct PVSCSICmdDescAbortCmd cmd = { 0 }; ++ ++ cmd.target = ctx->cmd->device->id; ++ cmd.context = pvscsi_map_context(adapter, ctx); ++ ++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd)); ++} ++ ++static void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter) ++{ ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0); ++} ++ ++static void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter) ++{ ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0); ++} ++ ++static int scsi_is_rw(unsigned char op) ++{ ++ return op == READ_6 || op == WRITE_6 || ++ op == READ_10 || op == WRITE_10 || ++ op == READ_12 || op == WRITE_12 || ++ op == READ_16 || op == WRITE_16; ++} ++ ++static void pvscsi_kick_io(const struct pvscsi_adapter *adapter, ++ unsigned char op) ++{ ++ if (scsi_is_rw(op)) ++ pvscsi_kick_rw_io(adapter); ++ else ++ pvscsi_process_request_ring(adapter); ++} ++ ++static void ll_adapter_reset(const struct pvscsi_adapter *adapter) ++{ ++ dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter); ++ ++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); ++} ++ ++static void ll_bus_reset(const struct pvscsi_adapter *adapter) ++{ ++ dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter); ++ ++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0); ++} ++ ++static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target) ++{ ++ struct PVSCSICmdDescResetDevice cmd = { 0 }; ++ ++ dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target); ++ ++ cmd.target = target; ++ ++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE, ++ &cmd, sizeof(cmd)); ++} ++ ++static void pvscsi_create_sg(struct pvscsi_ctx *ctx, ++ struct scatterlist *sg, unsigned count) ++{ ++ unsigned i; ++ struct PVSCSISGElement *sge; ++ ++ BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); ++ ++ sge = &ctx->sgl->sge[0]; ++ for (i = 0; i < count; i++, sg++) { ++ sge[i].addr = sg_dma_address(sg); ++ sge[i].length = sg_dma_len(sg); ++ sge[i].flags = 0; ++ } ++} ++ ++/* ++ * Map all data buffers for a command into PCI space and ++ * setup the scatter/gather list if needed. ++ */ ++static void pvscsi_map_buffers(struct pvscsi_adapter *adapter, ++ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd, ++ struct PVSCSIRingReqDesc *e) ++{ ++ unsigned count; ++ unsigned bufflen = scsi_bufflen(cmd); ++ struct scatterlist *sg; ++ ++ e->dataLen = bufflen; ++ e->dataAddr = 0; ++ if (bufflen == 0) ++ return; ++ ++ sg = scsi_sglist(cmd); ++ count = scsi_sg_count(cmd); ++ if (count != 0) { ++ int segs = scsi_dma_map(cmd); ++ if (segs > 1) { ++ pvscsi_create_sg(ctx, sg, segs); ++ ++ e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; ++ ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl, ++ SGL_SIZE, PCI_DMA_TODEVICE); ++ e->dataAddr = ctx->sglPA; ++ } else ++ e->dataAddr = sg_dma_address(sg); ++ } else { ++ /* ++ * In case there is no S/G list, scsi_sglist points ++ * directly to the buffer. ++ */ ++ ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen, ++ cmd->sc_data_direction); ++ e->dataAddr = ctx->dataPA; ++ } ++} ++ ++static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, ++ struct pvscsi_ctx *ctx) ++{ ++ struct scsi_cmnd *cmd; ++ unsigned bufflen; ++ ++ cmd = ctx->cmd; ++ bufflen = scsi_bufflen(cmd); ++ ++ if (bufflen != 0) { ++ unsigned count = scsi_sg_count(cmd); ++ ++ if (count != 0) { ++ scsi_dma_unmap(cmd); ++ if (ctx->sglPA) { ++ pci_unmap_single(adapter->dev, ctx->sglPA, ++ SGL_SIZE, PCI_DMA_TODEVICE); ++ ctx->sglPA = 0; ++ } ++ } else ++ pci_unmap_single(adapter->dev, ctx->dataPA, bufflen, ++ cmd->sc_data_direction); ++ } ++ if (cmd->sense_buffer) ++ pci_unmap_single(adapter->dev, ctx->sensePA, ++ SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); ++} ++ ++static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter) ++{ ++ adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE, ++ &adapter->ringStatePA); ++ if (!adapter->rings_state) ++ return -ENOMEM; ++ ++ adapter->req_pages = min(PVSCSI_MAX_NUM_PAGES_REQ_RING, ++ pvscsi_ring_pages); ++ adapter->req_depth = adapter->req_pages ++ * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; ++ adapter->req_ring = pci_alloc_consistent(adapter->dev, ++ adapter->req_pages * PAGE_SIZE, ++ &adapter->reqRingPA); ++ if (!adapter->req_ring) ++ return -ENOMEM; ++ ++ adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING, ++ pvscsi_ring_pages); ++ adapter->cmp_ring = pci_alloc_consistent(adapter->dev, ++ adapter->cmp_pages * PAGE_SIZE, ++ &adapter->cmpRingPA); ++ if (!adapter->cmp_ring) ++ return -ENOMEM; ++ ++ BUG_ON(!IS_ALIGNED(adapter->ringStatePA, PAGE_SIZE)); ++ BUG_ON(!IS_ALIGNED(adapter->reqRingPA, PAGE_SIZE)); ++ BUG_ON(!IS_ALIGNED(adapter->cmpRingPA, PAGE_SIZE)); ++ ++ if (!adapter->use_msg) ++ return 0; ++ ++ adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING, ++ pvscsi_msg_ring_pages); ++ adapter->msg_ring = pci_alloc_consistent(adapter->dev, ++ adapter->msg_pages * PAGE_SIZE, ++ &adapter->msgRingPA); ++ if (!adapter->msg_ring) ++ return -ENOMEM; ++ BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE)); ++ ++ return 0; ++} ++ ++static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter) ++{ ++ struct PVSCSICmdDescSetupRings cmd = { 0 }; ++ dma_addr_t base; ++ unsigned i; ++ ++ cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT; ++ cmd.reqRingNumPages = adapter->req_pages; ++ cmd.cmpRingNumPages = adapter->cmp_pages; ++ ++ base = adapter->reqRingPA; ++ for (i = 0; i < adapter->req_pages; i++) { ++ cmd.reqRingPPNs[i] = base >> PAGE_SHIFT; ++ base += PAGE_SIZE; ++ } ++ ++ base = adapter->cmpRingPA; ++ for (i = 0; i < adapter->cmp_pages; i++) { ++ cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT; ++ base += PAGE_SIZE; ++ } ++ ++ memset(adapter->rings_state, 0, PAGE_SIZE); ++ memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE); ++ memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE); ++ ++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS, ++ &cmd, sizeof(cmd)); ++ ++ if (adapter->use_msg) { ++ struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 }; ++ ++ cmd_msg.numPages = adapter->msg_pages; ++ ++ base = adapter->msgRingPA; ++ for (i = 0; i < adapter->msg_pages; i++) { ++ cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT; ++ base += PAGE_SIZE; ++ } ++ memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE); ++ ++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING, ++ &cmd_msg, sizeof(cmd_msg)); ++ } ++} ++ ++/* ++ * Pull a completion descriptor off and pass the completion back ++ * to the SCSI mid layer. ++ */ ++static void pvscsi_complete_request(struct pvscsi_adapter *adapter, ++ const struct PVSCSIRingCmpDesc *e) ++{ ++ struct pvscsi_ctx *ctx; ++ struct scsi_cmnd *cmd; ++ u32 btstat = e->hostStatus; ++ u32 sdstat = e->scsiStatus; ++ ++ ctx = pvscsi_get_context(adapter, e->context); ++ cmd = ctx->cmd; ++ pvscsi_unmap_buffers(adapter, ctx); ++ pvscsi_release_context(adapter, ctx); ++ cmd->result = 0; ++ ++ if (sdstat != SAM_STAT_GOOD && ++ (btstat == BTSTAT_SUCCESS || ++ btstat == BTSTAT_LINKED_COMMAND_COMPLETED || ++ btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { ++ cmd->result = (DID_OK << 16) | sdstat; ++ if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer) ++ cmd->result |= (DRIVER_SENSE << 24); ++ } else ++ switch (btstat) { ++ case BTSTAT_SUCCESS: ++ case BTSTAT_LINKED_COMMAND_COMPLETED: ++ case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: ++ /* If everything went fine, let's move on.. */ ++ cmd->result = (DID_OK << 16); ++ break; ++ ++ case BTSTAT_DATARUN: ++ case BTSTAT_DATA_UNDERRUN: ++ /* Report residual data in underruns */ ++ scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); ++ cmd->result = (DID_ERROR << 16); ++ break; ++ ++ case BTSTAT_SELTIMEO: ++ /* Our emulation returns this for non-connected devs */ ++ cmd->result = (DID_BAD_TARGET << 16); ++ break; ++ ++ case BTSTAT_LUNMISMATCH: ++ case BTSTAT_TAGREJECT: ++ case BTSTAT_BADMSG: ++ cmd->result = (DRIVER_INVALID << 24); ++ /* fall through */ ++ ++ case BTSTAT_HAHARDWARE: ++ case BTSTAT_INVPHASE: ++ case BTSTAT_HATIMEOUT: ++ case BTSTAT_NORESPONSE: ++ case BTSTAT_DISCONNECT: ++ case BTSTAT_HASOFTWARE: ++ case BTSTAT_BUSFREE: ++ case BTSTAT_SENSFAILED: ++ cmd->result |= (DID_ERROR << 16); ++ break; ++ ++ case BTSTAT_SENTRST: ++ case BTSTAT_RECVRST: ++ case BTSTAT_BUSRESET: ++ cmd->result = (DID_RESET << 16); ++ break; ++ ++ case BTSTAT_ABORTQUEUE: ++ cmd->result = (DID_ABORT << 16); ++ break; ++ ++ case BTSTAT_SCSIPARITY: ++ cmd->result = (DID_PARITY << 16); ++ break; ++ ++ default: ++ cmd->result = (DID_ERROR << 16); ++ scmd_printk(KERN_DEBUG, cmd, ++ "Unknown completion status: 0x%x\n", ++ btstat); ++ } ++ ++ dev_dbg(&cmd->device->sdev_gendev, ++ "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n", ++ cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat); ++ ++ cmd->scsi_done(cmd); ++} ++ ++/* ++ * barrier usage : Since the PVSCSI device is emulated, there could be cases ++ * where we may want to serialize some accesses between the driver and the ++ * emulation layer. We use compiler barriers instead of the more expensive ++ * memory barriers because PVSCSI is only supported on X86 which has strong ++ * memory access ordering. ++ */ ++static void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter) ++{ ++ struct PVSCSIRingsState *s = adapter->rings_state; ++ struct PVSCSIRingCmpDesc *ring = adapter->cmp_ring; ++ u32 cmp_entries = s->cmpNumEntriesLog2; ++ ++ while (s->cmpConsIdx != s->cmpProdIdx) { ++ struct PVSCSIRingCmpDesc *e = ring + (s->cmpConsIdx & ++ MASK(cmp_entries)); ++ /* ++ * This barrier() ensures that *e is not dereferenced while ++ * the device emulation still writes data into the slot. ++ * Since the device emulation advances s->cmpProdIdx only after ++ * updating the slot we want to check it first. ++ */ ++ barrier(); ++ pvscsi_complete_request(adapter, e); ++ /* ++ * This barrier() ensures that compiler doesn't reorder write ++ * to s->cmpConsIdx before the read of (*e) inside ++ * pvscsi_complete_request. Otherwise, device emulation may ++ * overwrite *e before we had a chance to read it. ++ */ ++ barrier(); ++ s->cmpConsIdx++; ++ } ++} ++ ++/* ++ * Translate a Linux SCSI request into a request ring entry. ++ */ ++static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, ++ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd) ++{ ++ struct PVSCSIRingsState *s; ++ struct PVSCSIRingReqDesc *e; ++ struct scsi_device *sdev; ++ u32 req_entries; ++ ++ s = adapter->rings_state; ++ sdev = cmd->device; ++ req_entries = s->reqNumEntriesLog2; ++ ++ /* ++ * If this condition holds, we might have room on the request ring, but ++ * we might not have room on the completion ring for the response. ++ * However, we have already ruled out this possibility - we would not ++ * have successfully allocated a context if it were true, since we only ++ * have one context per request entry. Check for it anyway, since it ++ * would be a serious bug. ++ */ ++ if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) { ++ scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: " ++ "ring full: reqProdIdx=%d cmpConsIdx=%d\n", ++ s->reqProdIdx, s->cmpConsIdx); ++ return -1; ++ } ++ ++ e = adapter->req_ring + (s->reqProdIdx & MASK(req_entries)); ++ ++ e->bus = sdev->channel; ++ e->target = sdev->id; ++ memset(e->lun, 0, sizeof(e->lun)); ++ e->lun[1] = sdev->lun; ++ ++ if (cmd->sense_buffer) { ++ ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer, ++ SCSI_SENSE_BUFFERSIZE, ++ PCI_DMA_FROMDEVICE); ++ e->senseAddr = ctx->sensePA; ++ e->senseLen = SCSI_SENSE_BUFFERSIZE; ++ } else { ++ e->senseLen = 0; ++ e->senseAddr = 0; ++ } ++ e->cdbLen = cmd->cmd_len; ++ e->vcpuHint = smp_processor_id(); ++ memcpy(e->cdb, cmd->cmnd, e->cdbLen); ++ ++ e->tag = SIMPLE_QUEUE_TAG; ++ if (sdev->tagged_supported && ++ (cmd->tag == HEAD_OF_QUEUE_TAG || ++ cmd->tag == ORDERED_QUEUE_TAG)) ++ e->tag = cmd->tag; ++ ++ if (cmd->sc_data_direction == DMA_FROM_DEVICE) ++ e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST; ++ else if (cmd->sc_data_direction == DMA_TO_DEVICE) ++ e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE; ++ else if (cmd->sc_data_direction == DMA_NONE) ++ e->flags = PVSCSI_FLAG_CMD_DIR_NONE; ++ else ++ e->flags = 0; ++ ++ pvscsi_map_buffers(adapter, ctx, cmd, e); ++ ++ e->context = pvscsi_map_context(adapter, ctx); ++ ++ barrier(); ++ ++ s->reqProdIdx++; ++ ++ return 0; ++} ++ ++static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) ++{ ++ struct Scsi_Host *host = cmd->device->host; ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ struct pvscsi_ctx *ctx; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ ++ ctx = pvscsi_acquire_context(adapter, cmd); ++ if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) { ++ if (ctx) ++ pvscsi_release_context(adapter, ctx); ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ return SCSI_MLQUEUE_HOST_BUSY; ++ } ++ ++ cmd->scsi_done = done; ++ ++ dev_dbg(&cmd->device->sdev_gendev, ++ "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]); ++ ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ ++ pvscsi_kick_io(adapter, cmd->cmnd[0]); ++ ++ return 0; ++} ++ ++static int pvscsi_abort(struct scsi_cmnd *cmd) ++{ ++ struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); ++ struct pvscsi_ctx *ctx; ++ unsigned long flags; ++ ++ scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", ++ adapter->host->host_no, cmd); ++ ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ ++ /* ++ * Poll the completion ring first - we might be trying to abort ++ * a command that is waiting to be dispatched in the completion ring. ++ */ ++ pvscsi_process_completion_ring(adapter); ++ ++ /* ++ * If there is no context for the command, it either already succeeded ++ * or else was never properly issued. Not our problem. ++ */ ++ ctx = pvscsi_find_context(adapter, cmd); ++ if (!ctx) { ++ scmd_printk(KERN_DEBUG, cmd, "Failed to abort cmd %p\n", cmd); ++ goto out; ++ } ++ ++ pvscsi_abort_cmd(adapter, ctx); ++ ++ pvscsi_process_completion_ring(adapter); ++ ++out: ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ return SUCCESS; ++} ++ ++/* ++ * Abort all outstanding requests. This is only safe to use if the completion ++ * ring will never be walked again or the device has been reset, because it ++ * destroys the 1-1 mapping between context field passed to emulation and our ++ * request structure. ++ */ ++static void pvscsi_reset_all(struct pvscsi_adapter *adapter) ++{ ++ unsigned i; ++ ++ for (i = 0; i < adapter->req_depth; i++) { ++ struct pvscsi_ctx *ctx = &adapter->cmd_map[i]; ++ struct scsi_cmnd *cmd = ctx->cmd; ++ if (cmd) { ++ scmd_printk(KERN_ERR, cmd, ++ "Forced reset on cmd %p\n", cmd); ++ pvscsi_unmap_buffers(adapter, ctx); ++ pvscsi_release_context(adapter, ctx); ++ cmd->result = (DID_RESET << 16); ++ cmd->scsi_done(cmd); ++ } ++ } ++} ++ ++static int pvscsi_host_reset(struct scsi_cmnd *cmd) ++{ ++ struct Scsi_Host *host = cmd->device->host; ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ unsigned long flags; ++ bool use_msg; ++ ++ scmd_printk(KERN_INFO, cmd, "SCSI Host reset\n"); ++ ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ ++ use_msg = adapter->use_msg; ++ ++ if (use_msg) { ++ adapter->use_msg = 0; ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ ++ /* ++ * Now that we know that the ISR won't add more work on the ++ * workqueue we can safely flush any outstanding work. ++ */ ++ flush_workqueue(adapter->workqueue); ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ } ++ ++ /* ++ * We're going to tear down the entire ring structure and set it back ++ * up, so stalling new requests until all completions are flushed and ++ * the rings are back in place. ++ */ ++ ++ pvscsi_process_request_ring(adapter); ++ ++ ll_adapter_reset(adapter); ++ ++ /* ++ * Now process any completions. Note we do this AFTER adapter reset, ++ * which is strange, but stops races where completions get posted ++ * between processing the ring and issuing the reset. The backend will ++ * not touch the ring memory after reset, so the immediately pre-reset ++ * completion ring state is still valid. ++ */ ++ pvscsi_process_completion_ring(adapter); ++ ++ pvscsi_reset_all(adapter); ++ adapter->use_msg = use_msg; ++ pvscsi_setup_all_rings(adapter); ++ pvscsi_unmask_intr(adapter); ++ ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ ++ return SUCCESS; ++} ++ ++static int pvscsi_bus_reset(struct scsi_cmnd *cmd) ++{ ++ struct Scsi_Host *host = cmd->device->host; ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ unsigned long flags; ++ ++ scmd_printk(KERN_INFO, cmd, "SCSI Bus reset\n"); ++ ++ /* ++ * We don't want to queue new requests for this bus after ++ * flushing all pending requests to emulation, since new ++ * requests could then sneak in during this bus reset phase, ++ * so take the lock now. ++ */ ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ ++ pvscsi_process_request_ring(adapter); ++ ll_bus_reset(adapter); ++ pvscsi_process_completion_ring(adapter); ++ ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ ++ return SUCCESS; ++} ++ ++static int pvscsi_device_reset(struct scsi_cmnd *cmd) ++{ ++ struct Scsi_Host *host = cmd->device->host; ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ unsigned long flags; ++ ++ scmd_printk(KERN_INFO, cmd, "SCSI device reset on scsi%u:%u\n", ++ host->host_no, cmd->device->id); ++ ++ /* ++ * We don't want to queue new requests for this device after flushing ++ * all pending requests to emulation, since new requests could then ++ * sneak in during this device reset phase, so take the lock now. ++ */ ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ ++ pvscsi_process_request_ring(adapter); ++ ll_device_reset(adapter, cmd->device->id); ++ pvscsi_process_completion_ring(adapter); ++ ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ ++ return SUCCESS; ++} ++ ++static struct scsi_host_template pvscsi_template; ++ ++static const char *pvscsi_info(struct Scsi_Host *host) ++{ ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ static char buf[256]; ++ ++ sprintf(buf, "VMware PVSCSI storage adapter rev %d, req/cmp/msg rings: " ++ "%u/%u/%u pages, cmd_per_lun=%u", adapter->rev, ++ adapter->req_pages, adapter->cmp_pages, adapter->msg_pages, ++ pvscsi_template.cmd_per_lun); ++ ++ return buf; ++} ++ ++static struct scsi_host_template pvscsi_template = { ++ .module = THIS_MODULE, ++ .name = "VMware PVSCSI Host Adapter", ++ .proc_name = "vmw_pvscsi", ++ .info = pvscsi_info, ++ .queuecommand = pvscsi_queue, ++ .this_id = -1, ++ .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT, ++ .dma_boundary = UINT_MAX, ++ .max_sectors = 0xffff, ++ .use_clustering = ENABLE_CLUSTERING, ++ .eh_abort_handler = pvscsi_abort, ++ .eh_device_reset_handler = pvscsi_device_reset, ++ .eh_bus_reset_handler = pvscsi_bus_reset, ++ .eh_host_reset_handler = pvscsi_host_reset, ++}; ++ ++static void pvscsi_process_msg(const struct pvscsi_adapter *adapter, ++ const struct PVSCSIRingMsgDesc *e) ++{ ++ struct PVSCSIRingsState *s = adapter->rings_state; ++ struct Scsi_Host *host = adapter->host; ++ struct scsi_device *sdev; ++ ++ printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n", ++ e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2); ++ ++ BUILD_BUG_ON(PVSCSI_MSG_LAST != 2); ++ ++ if (e->type == PVSCSI_MSG_DEV_ADDED) { ++ struct PVSCSIMsgDescDevStatusChanged *desc; ++ desc = (struct PVSCSIMsgDescDevStatusChanged *)e; ++ ++ printk(KERN_INFO ++ "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n", ++ desc->bus, desc->target, desc->lun[1]); ++ ++ if (!scsi_host_get(host)) ++ return; ++ ++ sdev = scsi_device_lookup(host, desc->bus, desc->target, ++ desc->lun[1]); ++ if (sdev) { ++ printk(KERN_INFO "vmw_pvscsi: device already exists\n"); ++ scsi_device_put(sdev); ++ } else ++ scsi_add_device(adapter->host, desc->bus, ++ desc->target, desc->lun[1]); ++ ++ scsi_host_put(host); ++ } else if (e->type == PVSCSI_MSG_DEV_REMOVED) { ++ struct PVSCSIMsgDescDevStatusChanged *desc; ++ desc = (struct PVSCSIMsgDescDevStatusChanged *)e; ++ ++ printk(KERN_INFO ++ "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n", ++ desc->bus, desc->target, desc->lun[1]); ++ ++ if (!scsi_host_get(host)) ++ return; ++ ++ sdev = scsi_device_lookup(host, desc->bus, desc->target, ++ desc->lun[1]); ++ if (sdev) { ++ scsi_remove_device(sdev); ++ scsi_device_put(sdev); ++ } else ++ printk(KERN_INFO ++ "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n", ++ desc->bus, desc->target, desc->lun[1]); ++ ++ scsi_host_put(host); ++ } ++} ++ ++static int pvscsi_msg_pending(const struct pvscsi_adapter *adapter) ++{ ++ struct PVSCSIRingsState *s = adapter->rings_state; ++ ++ return s->msgProdIdx != s->msgConsIdx; ++} ++ ++static void pvscsi_process_msg_ring(const struct pvscsi_adapter *adapter) ++{ ++ struct PVSCSIRingsState *s = adapter->rings_state; ++ struct PVSCSIRingMsgDesc *ring = adapter->msg_ring; ++ u32 msg_entries = s->msgNumEntriesLog2; ++ ++ while (pvscsi_msg_pending(adapter)) { ++ struct PVSCSIRingMsgDesc *e = ring + (s->msgConsIdx & ++ MASK(msg_entries)); ++ ++ barrier(); ++ pvscsi_process_msg(adapter, e); ++ barrier(); ++ s->msgConsIdx++; ++ } ++} ++ ++static void pvscsi_msg_workqueue_handler(struct work_struct *data) ++{ ++ struct pvscsi_adapter *adapter; ++ ++ adapter = container_of(data, struct pvscsi_adapter, work); ++ ++ pvscsi_process_msg_ring(adapter); ++} ++ ++static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter) ++{ ++ char name[32]; ++ ++ if (!pvscsi_use_msg) ++ return 0; ++ ++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, ++ PVSCSI_CMD_SETUP_MSG_RING); ++ ++ if (pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS) == -1) ++ return 0; ++ ++ snprintf(name, sizeof(name), ++ "vmw_pvscsi_wq_%u", adapter->host->host_no); ++ ++ adapter->workqueue = create_singlethread_workqueue(name); ++ if (!adapter->workqueue) { ++ printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n"); ++ return 0; ++ } ++ INIT_WORK(&adapter->work, pvscsi_msg_workqueue_handler); ++ ++ return 1; ++} ++ ++static irqreturn_t pvscsi_isr(int irq, void *devp) ++{ ++ struct pvscsi_adapter *adapter = devp; ++ int handled; ++ ++ if (adapter->use_msi || adapter->use_msix) ++ handled = true; ++ else { ++ u32 val = pvscsi_read_intr_status(adapter); ++ handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0; ++ if (handled) ++ pvscsi_write_intr_status(devp, val); ++ } ++ ++ if (handled) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->hw_lock, flags); ++ ++ pvscsi_process_completion_ring(adapter); ++ if (adapter->use_msg && pvscsi_msg_pending(adapter)) ++ queue_work(adapter->workqueue, &adapter->work); ++ ++ spin_unlock_irqrestore(&adapter->hw_lock, flags); ++ } ++ ++ return IRQ_RETVAL(handled); ++} ++ ++static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) ++{ ++ struct pvscsi_ctx *ctx = adapter->cmd_map; ++ unsigned i; ++ ++ for (i = 0; i < adapter->req_depth; ++i, ++ctx) ++ kfree(ctx->sgl); ++} ++ ++static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, int *irq) ++{ ++ struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; ++ int ret; ++ ++ ret = pci_enable_msix(adapter->dev, &entry, 1); ++ if (ret) ++ return ret; ++ ++ *irq = entry.vector; ++ ++ return 0; ++} ++ ++static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) ++{ ++ if (adapter->irq) { ++ free_irq(adapter->irq, adapter); ++ adapter->irq = 0; ++ } ++ if (adapter->use_msi) { ++ pci_disable_msi(adapter->dev); ++ adapter->use_msi = 0; ++ } else if (adapter->use_msix) { ++ pci_disable_msix(adapter->dev); ++ adapter->use_msix = 0; ++ } ++} ++ ++static void pvscsi_release_resources(struct pvscsi_adapter *adapter) ++{ ++ pvscsi_shutdown_intr(adapter); ++ ++ if (adapter->workqueue) ++ destroy_workqueue(adapter->workqueue); ++ ++ if (adapter->mmioBase) ++ pci_iounmap(adapter->dev, adapter->mmioBase); ++ ++ pci_release_regions(adapter->dev); ++ ++ if (adapter->cmd_map) { ++ pvscsi_free_sgls(adapter); ++ kfree(adapter->cmd_map); ++ } ++ ++ if (adapter->rings_state) ++ pci_free_consistent(adapter->dev, PAGE_SIZE, ++ adapter->rings_state, adapter->ringStatePA); ++ ++ if (adapter->req_ring) ++ pci_free_consistent(adapter->dev, ++ adapter->req_pages * PAGE_SIZE, ++ adapter->req_ring, adapter->reqRingPA); ++ ++ if (adapter->cmp_ring) ++ pci_free_consistent(adapter->dev, ++ adapter->cmp_pages * PAGE_SIZE, ++ adapter->cmp_ring, adapter->cmpRingPA); ++ ++ if (adapter->msg_ring) ++ pci_free_consistent(adapter->dev, ++ adapter->msg_pages * PAGE_SIZE, ++ adapter->msg_ring, adapter->msgRingPA); ++} ++ ++/* ++ * Allocate scatter gather lists. ++ * ++ * These are statically allocated. Trying to be clever was not worth it. ++ * ++ * Dynamic allocation can fail, and we can't go deeep into the memory ++ * allocator, since we're a SCSI driver, and trying too hard to allocate ++ * memory might generate disk I/O. We also don't want to fail disk I/O ++ * in that case because we can't get an allocation - the I/O could be ++ * trying to swap out data to free memory. Since that is pathological, ++ * just use a statically allocated scatter list. ++ * ++ */ ++static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter) ++{ ++ struct pvscsi_ctx *ctx; ++ int i; ++ ++ ctx = adapter->cmd_map; ++ BUILD_BUG_ON(sizeof(struct pvscsi_sg_list) > SGL_SIZE); ++ ++ for (i = 0; i < adapter->req_depth; ++i, ++ctx) { ++ ctx->sgl = kmalloc(SGL_SIZE, GFP_KERNEL); ++ ctx->sglPA = 0; ++ BUG_ON(!IS_ALIGNED(((unsigned long)ctx->sgl), PAGE_SIZE)); ++ if (!ctx->sgl) { ++ for (; i >= 0; --i, --ctx) { ++ kfree(ctx->sgl); ++ ctx->sgl = NULL; ++ } ++ return -ENOMEM; ++ } ++ } ++ ++ return 0; ++} ++ ++static int __devinit pvscsi_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ struct pvscsi_adapter *adapter; ++ struct Scsi_Host *host; ++ unsigned int i; ++ int error; ++ ++ error = -ENODEV; ++ ++ if (pci_enable_device(pdev)) ++ return error; ++ ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 && ++ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { ++ printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n"); ++ } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 && ++ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) { ++ printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n"); ++ } else { ++ printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n"); ++ goto out_disable_device; ++ } ++ ++ pvscsi_template.can_queue = ++ min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) * ++ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; ++ pvscsi_template.cmd_per_lun = ++ min(pvscsi_template.can_queue, pvscsi_cmd_per_lun); ++ host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter)); ++ if (!host) { ++ printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n"); ++ goto out_disable_device; ++ } ++ ++ adapter = shost_priv(host); ++ memset(adapter, 0, sizeof(*adapter)); ++ adapter->dev = pdev; ++ adapter->host = host; ++ ++ spin_lock_init(&adapter->hw_lock); ++ ++ host->max_channel = 0; ++ host->max_id = 16; ++ host->max_lun = 1; ++ host->max_cmd_len = 16; ++ ++ adapter->rev = pdev->revision; ++ ++ if (pci_request_regions(pdev, "vmw_pvscsi")) { ++ printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n"); ++ goto out_free_host; ++ } ++ ++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { ++ if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) ++ continue; ++ ++ if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_SIZE) ++ continue; ++ ++ break; ++ } ++ ++ if (i == DEVICE_COUNT_RESOURCE) { ++ printk(KERN_ERR ++ "vmw_pvscsi: adapter has no suitable MMIO region\n"); ++ goto out_release_resources; ++ } ++ ++ adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE); ++ ++ if (!adapter->mmioBase) { ++ printk(KERN_ERR ++ "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n", ++ i, PVSCSI_MEM_SPACE_SIZE); ++ goto out_release_resources; ++ } ++ ++ pci_set_master(pdev); ++ pci_set_drvdata(pdev, host); ++ ++ ll_adapter_reset(adapter); ++ ++ adapter->use_msg = pvscsi_setup_msg_workqueue(adapter); ++ ++ error = pvscsi_allocate_rings(adapter); ++ if (error) { ++ printk(KERN_ERR "vmw_pvscsi: unable to allocate ring memory\n"); ++ goto out_release_resources; ++ } ++ ++ /* ++ * From this point on we should reset the adapter if anything goes ++ * wrong. ++ */ ++ pvscsi_setup_all_rings(adapter); ++ ++ adapter->cmd_map = kcalloc(adapter->req_depth, ++ sizeof(struct pvscsi_ctx), GFP_KERNEL); ++ if (!adapter->cmd_map) { ++ printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n"); ++ error = -ENOMEM; ++ goto out_reset_adapter; ++ } ++ ++ INIT_LIST_HEAD(&adapter->cmd_pool); ++ for (i = 0; i < adapter->req_depth; i++) { ++ struct pvscsi_ctx *ctx = adapter->cmd_map + i; ++ list_add(&ctx->list, &adapter->cmd_pool); ++ } ++ ++ error = pvscsi_allocate_sg(adapter); ++ if (error) { ++ printk(KERN_ERR "vmw_pvscsi: unable to allocate s/g table\n"); ++ goto out_reset_adapter; ++ } ++ ++ if (!pvscsi_disable_msix && ++ pvscsi_setup_msix(adapter, &adapter->irq) == 0) { ++ printk(KERN_INFO "vmw_pvscsi: using MSI-X\n"); ++ adapter->use_msix = 1; ++ } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) { ++ printk(KERN_INFO "vmw_pvscsi: using MSI\n"); ++ adapter->use_msi = 1; ++ adapter->irq = pdev->irq; ++ } else { ++ printk(KERN_INFO "vmw_pvscsi: using INTx\n"); ++ adapter->irq = pdev->irq; ++ } ++ ++ error = request_irq(adapter->irq, pvscsi_isr, IRQF_SHARED, ++ "vmw_pvscsi", adapter); ++ if (error) { ++ printk(KERN_ERR ++ "vmw_pvscsi: unable to request IRQ: %d\n", error); ++ adapter->irq = 0; ++ goto out_reset_adapter; ++ } ++ ++ error = scsi_add_host(host, &pdev->dev); ++ if (error) { ++ printk(KERN_ERR ++ "vmw_pvscsi: scsi_add_host failed: %d\n", error); ++ goto out_reset_adapter; ++ } ++ ++ dev_info(&pdev->dev, "VMware PVSCSI rev %d host #%u\n", ++ adapter->rev, host->host_no); ++ ++ pvscsi_unmask_intr(adapter); ++ ++ scsi_scan_host(host); ++ ++ return 0; ++ ++out_reset_adapter: ++ ll_adapter_reset(adapter); ++out_release_resources: ++ pvscsi_release_resources(adapter); ++out_free_host: ++ scsi_host_put(host); ++out_disable_device: ++ pci_set_drvdata(pdev, NULL); ++ pci_disable_device(pdev); ++ ++ return error; ++} ++ ++static void __pvscsi_shutdown(struct pvscsi_adapter *adapter) ++{ ++ pvscsi_mask_intr(adapter); ++ ++ if (adapter->workqueue) ++ flush_workqueue(adapter->workqueue); ++ ++ pvscsi_shutdown_intr(adapter); ++ ++ pvscsi_process_request_ring(adapter); ++ pvscsi_process_completion_ring(adapter); ++ ll_adapter_reset(adapter); ++} ++ ++static void pvscsi_shutdown(struct pci_dev *dev) ++{ ++ struct Scsi_Host *host = pci_get_drvdata(dev); ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ ++ __pvscsi_shutdown(adapter); ++} ++ ++static void pvscsi_remove(struct pci_dev *pdev) ++{ ++ struct Scsi_Host *host = pci_get_drvdata(pdev); ++ struct pvscsi_adapter *adapter = shost_priv(host); ++ ++ scsi_remove_host(host); ++ ++ __pvscsi_shutdown(adapter); ++ pvscsi_release_resources(adapter); ++ ++ scsi_host_put(host); ++ ++ pci_set_drvdata(pdev, NULL); ++ pci_disable_device(pdev); ++} ++ ++static struct pci_driver pvscsi_pci_driver = { ++ .name = "vmw_pvscsi", ++ .id_table = pvscsi_pci_tbl, ++ .probe = pvscsi_probe, ++ .remove = __devexit_p(pvscsi_remove), ++ .shutdown = pvscsi_shutdown, ++}; ++ ++static int __init pvscsi_init(void) ++{ ++ pr_info("%s - version %s\n", ++ PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING); ++ return pci_register_driver(&pvscsi_pci_driver); ++} ++ ++static void __exit pvscsi_exit(void) ++{ ++ pci_unregister_driver(&pvscsi_pci_driver); ++} ++ ++module_init(pvscsi_init); ++module_exit(pvscsi_exit); +diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h +new file mode 100644 +index 0000000..62e36e7 +--- /dev/null ++++ b/drivers/scsi/vmw_pvscsi.h +@@ -0,0 +1,397 @@ ++/* ++ * VMware PVSCSI header file ++ * ++ * Copyright (C) 2008-2009, VMware, 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; version 2 of the License and no 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. ++ * ++ * Maintained by: Alok N Kataria <akataria@vmware.com> ++ * ++ */ ++ ++#ifndef _VMW_PVSCSI_H_ ++#define _VMW_PVSCSI_H_ ++ ++#include <linux/types.h> ++ ++#define PVSCSI_DRIVER_VERSION_STRING "1.0.1.0-k" ++ ++#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128 ++ ++#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ ++ ++#define PCI_VENDOR_ID_VMWARE 0x15AD ++#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 ++ ++/* ++ * host adapter status/error codes ++ */ ++enum HostBusAdapterStatus { ++ BTSTAT_SUCCESS = 0x00, /* CCB complete normally with no errors */ ++ BTSTAT_LINKED_COMMAND_COMPLETED = 0x0a, ++ BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b, ++ BTSTAT_DATA_UNDERRUN = 0x0c, ++ BTSTAT_SELTIMEO = 0x11, /* SCSI selection timeout */ ++ BTSTAT_DATARUN = 0x12, /* data overrun/underrun */ ++ BTSTAT_BUSFREE = 0x13, /* unexpected bus free */ ++ BTSTAT_INVPHASE = 0x14, /* invalid bus phase or sequence requested by target */ ++ BTSTAT_LUNMISMATCH = 0x17, /* linked CCB has different LUN from first CCB */ ++ BTSTAT_SENSFAILED = 0x1b, /* auto request sense failed */ ++ BTSTAT_TAGREJECT = 0x1c, /* SCSI II tagged queueing message rejected by target */ ++ BTSTAT_BADMSG = 0x1d, /* unsupported message received by the host adapter */ ++ BTSTAT_HAHARDWARE = 0x20, /* host adapter hardware failed */ ++ BTSTAT_NORESPONSE = 0x21, /* target did not respond to SCSI ATN, sent a SCSI RST */ ++ BTSTAT_SENTRST = 0x22, /* host adapter asserted a SCSI RST */ ++ BTSTAT_RECVRST = 0x23, /* other SCSI devices asserted a SCSI RST */ ++ BTSTAT_DISCONNECT = 0x24, /* target device reconnected improperly (w/o tag) */ ++ BTSTAT_BUSRESET = 0x25, /* host adapter issued BUS device reset */ ++ BTSTAT_ABORTQUEUE = 0x26, /* abort queue generated */ ++ BTSTAT_HASOFTWARE = 0x27, /* host adapter software error */ ++ BTSTAT_HATIMEOUT = 0x30, /* host adapter hardware timeout error */ ++ BTSTAT_SCSIPARITY = 0x34, /* SCSI parity error detected */ ++}; ++ ++/* ++ * Register offsets. ++ * ++ * These registers are accessible both via i/o space and mm i/o. ++ */ ++ ++enum PVSCSIRegOffset { ++ PVSCSI_REG_OFFSET_COMMAND = 0x0, ++ PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4, ++ PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8, ++ PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100, ++ PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104, ++ PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108, ++ PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c, ++ PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c, ++ PVSCSI_REG_OFFSET_INTR_MASK = 0x2010, ++ PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014, ++ PVSCSI_REG_OFFSET_DEBUG = 0x3018, ++ PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018, ++}; ++ ++/* ++ * Virtual h/w commands. ++ */ ++ ++enum PVSCSICommands { ++ PVSCSI_CMD_FIRST = 0, /* has to be first */ ++ ++ PVSCSI_CMD_ADAPTER_RESET = 1, ++ PVSCSI_CMD_ISSUE_SCSI = 2, ++ PVSCSI_CMD_SETUP_RINGS = 3, ++ PVSCSI_CMD_RESET_BUS = 4, ++ PVSCSI_CMD_RESET_DEVICE = 5, ++ PVSCSI_CMD_ABORT_CMD = 6, ++ PVSCSI_CMD_CONFIG = 7, ++ PVSCSI_CMD_SETUP_MSG_RING = 8, ++ PVSCSI_CMD_DEVICE_UNPLUG = 9, ++ ++ PVSCSI_CMD_LAST = 10 /* has to be last */ ++}; ++ ++/* ++ * Command descriptor for PVSCSI_CMD_RESET_DEVICE -- ++ */ ++ ++struct PVSCSICmdDescResetDevice { ++ u32 target; ++ u8 lun[8]; ++} __packed; ++ ++/* ++ * Command descriptor for PVSCSI_CMD_ABORT_CMD -- ++ * ++ * - currently does not support specifying the LUN. ++ * - _pad should be 0. ++ */ ++ ++struct PVSCSICmdDescAbortCmd { ++ u64 context; ++ u32 target; ++ u32 _pad; ++} __packed; ++ ++/* ++ * Command descriptor for PVSCSI_CMD_SETUP_RINGS -- ++ * ++ * Notes: ++ * - reqRingNumPages and cmpRingNumPages need to be power of two. ++ * - reqRingNumPages and cmpRingNumPages need to be different from 0, ++ * - reqRingNumPages and cmpRingNumPages need to be inferior to ++ * PVSCSI_SETUP_RINGS_MAX_NUM_PAGES. ++ */ ++ ++#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32 ++struct PVSCSICmdDescSetupRings { ++ u32 reqRingNumPages; ++ u32 cmpRingNumPages; ++ u64 ringsStatePPN; ++ u64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES]; ++ u64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES]; ++} __packed; ++ ++/* ++ * Command descriptor for PVSCSI_CMD_SETUP_MSG_RING -- ++ * ++ * Notes: ++ * - this command was not supported in the initial revision of the h/w ++ * interface. Before using it, you need to check that it is supported by ++ * writing PVSCSI_CMD_SETUP_MSG_RING to the 'command' register, then ++ * immediately after read the 'command status' register: ++ * * a value of -1 means that the cmd is NOT supported, ++ * * a value != -1 means that the cmd IS supported. ++ * If it's supported the 'command status' register should return: ++ * sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(u32). ++ * - this command should be issued _after_ the usual SETUP_RINGS so that the ++ * RingsState page is already setup. If not, the command is a nop. ++ * - numPages needs to be a power of two, ++ * - numPages needs to be different from 0, ++ * - _pad should be zero. ++ */ ++ ++#define PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES 16 ++ ++struct PVSCSICmdDescSetupMsgRing { ++ u32 numPages; ++ u32 _pad; ++ u64 ringPPNs[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES]; ++} __packed; ++ ++enum PVSCSIMsgType { ++ PVSCSI_MSG_DEV_ADDED = 0, ++ PVSCSI_MSG_DEV_REMOVED = 1, ++ PVSCSI_MSG_LAST = 2, ++}; ++ ++/* ++ * Msg descriptor. ++ * ++ * sizeof(struct PVSCSIRingMsgDesc) == 128. ++ * ++ * - type is of type enum PVSCSIMsgType. ++ * - the content of args depend on the type of event being delivered. ++ */ ++ ++struct PVSCSIRingMsgDesc { ++ u32 type; ++ u32 args[31]; ++} __packed; ++ ++struct PVSCSIMsgDescDevStatusChanged { ++ u32 type; /* PVSCSI_MSG_DEV _ADDED / _REMOVED */ ++ u32 bus; ++ u32 target; ++ u8 lun[8]; ++ u32 pad[27]; ++} __packed; ++ ++/* ++ * Rings state. ++ * ++ * - the fields: ++ * . msgProdIdx, ++ * . msgConsIdx, ++ * . msgNumEntriesLog2, ++ * .. are only used once the SETUP_MSG_RING cmd has been issued. ++ * - '_pad' helps to ensure that the msg related fields are on their own ++ * cache-line. ++ */ ++ ++struct PVSCSIRingsState { ++ u32 reqProdIdx; ++ u32 reqConsIdx; ++ u32 reqNumEntriesLog2; ++ ++ u32 cmpProdIdx; ++ u32 cmpConsIdx; ++ u32 cmpNumEntriesLog2; ++ ++ u8 _pad[104]; ++ ++ u32 msgProdIdx; ++ u32 msgConsIdx; ++ u32 msgNumEntriesLog2; ++} __packed; ++ ++/* ++ * Request descriptor. ++ * ++ * sizeof(RingReqDesc) = 128 ++ * ++ * - context: is a unique identifier of a command. It could normally be any ++ * 64bit value, however we currently store it in the serialNumber variable ++ * of struct SCSI_Command, so we have the following restrictions due to the ++ * way this field is handled in the vmkernel storage stack: ++ * * this value can't be 0, ++ * * the upper 32bit need to be 0 since serialNumber is as a u32. ++ * Currently tracked as PR 292060. ++ * - dataLen: contains the total number of bytes that need to be transferred. ++ * - dataAddr: ++ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is set: dataAddr is the PA of the first ++ * s/g table segment, each s/g segment is entirely contained on a single ++ * page of physical memory, ++ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is NOT set, then dataAddr is the PA of ++ * the buffer used for the DMA transfer, ++ * - flags: ++ * * PVSCSI_FLAG_CMD_WITH_SG_LIST: see dataAddr above, ++ * * PVSCSI_FLAG_CMD_DIR_NONE: no DMA involved, ++ * * PVSCSI_FLAG_CMD_DIR_TOHOST: transfer from device to main memory, ++ * * PVSCSI_FLAG_CMD_DIR_TODEVICE: transfer from main memory to device, ++ * * PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB: reserved to handle CDBs larger than ++ * 16bytes. To be specified. ++ * - vcpuHint: vcpuId of the processor that will be most likely waiting for the ++ * completion of the i/o. For guest OSes that use lowest priority message ++ * delivery mode (such as windows), we use this "hint" to deliver the ++ * completion action to the proper vcpu. For now, we can use the vcpuId of ++ * the processor that initiated the i/o as a likely candidate for the vcpu ++ * that will be waiting for the completion.. ++ * - bus should be 0: we currently only support bus 0 for now. ++ * - unused should be zero'd. ++ */ ++ ++#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0) ++#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1) ++#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2) ++#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3) ++#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4) ++ ++struct PVSCSIRingReqDesc { ++ u64 context; ++ u64 dataAddr; ++ u64 dataLen; ++ u64 senseAddr; ++ u32 senseLen; ++ u32 flags; ++ u8 cdb[16]; ++ u8 cdbLen; ++ u8 lun[8]; ++ u8 tag; ++ u8 bus; ++ u8 target; ++ u8 vcpuHint; ++ u8 unused[59]; ++} __packed; ++ ++/* ++ * Scatter-gather list management. ++ * ++ * As described above, when PVSCSI_FLAG_CMD_WITH_SG_LIST is set in the ++ * RingReqDesc.flags, then RingReqDesc.dataAddr is the PA of the first s/g ++ * table segment. ++ * ++ * - each segment of the s/g table contain a succession of struct ++ * PVSCSISGElement. ++ * - each segment is entirely contained on a single physical page of memory. ++ * - a "chain" s/g element has the flag PVSCSI_SGE_FLAG_CHAIN_ELEMENT set in ++ * PVSCSISGElement.flags and in this case: ++ * * addr is the PA of the next s/g segment, ++ * * length is undefined, assumed to be 0. ++ */ ++ ++struct PVSCSISGElement { ++ u64 addr; ++ u32 length; ++ u32 flags; ++} __packed; ++ ++/* ++ * Completion descriptor. ++ * ++ * sizeof(RingCmpDesc) = 32 ++ * ++ * - context: identifier of the command. The same thing that was specified ++ * under "context" as part of struct RingReqDesc at initiation time, ++ * - dataLen: number of bytes transferred for the actual i/o operation, ++ * - senseLen: number of bytes written into the sense buffer, ++ * - hostStatus: adapter status, ++ * - scsiStatus: device status, ++ * - _pad should be zero. ++ */ ++ ++struct PVSCSIRingCmpDesc { ++ u64 context; ++ u64 dataLen; ++ u32 senseLen; ++ u16 hostStatus; ++ u16 scsiStatus; ++ u32 _pad[2]; ++} __packed; ++ ++/* ++ * Interrupt status / IRQ bits. ++ */ ++ ++#define PVSCSI_INTR_CMPL_0 (1 << 0) ++#define PVSCSI_INTR_CMPL_1 (1 << 1) ++#define PVSCSI_INTR_CMPL_MASK MASK(2) ++ ++#define PVSCSI_INTR_MSG_0 (1 << 2) ++#define PVSCSI_INTR_MSG_1 (1 << 3) ++#define PVSCSI_INTR_MSG_MASK (MASK(2) << 2) ++ ++#define PVSCSI_INTR_ALL_SUPPORTED MASK(4) ++ ++/* ++ * Number of MSI-X vectors supported. ++ */ ++#define PVSCSI_MAX_INTRS 24 ++ ++/* ++ * Enumeration of supported MSI-X vectors ++ */ ++#define PVSCSI_VECTOR_COMPLETION 0 ++ ++/* ++ * Misc constants for the rings. ++ */ ++ ++#define PVSCSI_MAX_NUM_PAGES_REQ_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES ++#define PVSCSI_MAX_NUM_PAGES_CMP_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES ++#define PVSCSI_MAX_NUM_PAGES_MSG_RING PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES ++ ++#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE \ ++ (PAGE_SIZE / sizeof(struct PVSCSIRingReqDesc)) ++ ++#define PVSCSI_MAX_REQ_QUEUE_DEPTH \ ++ (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE) ++ ++#define PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES 1 ++#define PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES 1 ++#define PVSCSI_MEM_SPACE_MISC_NUM_PAGES 2 ++#define PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES 2 ++#define PVSCSI_MEM_SPACE_MSIX_NUM_PAGES 2 ++ ++enum PVSCSIMemSpace { ++ PVSCSI_MEM_SPACE_COMMAND_PAGE = 0, ++ PVSCSI_MEM_SPACE_INTR_STATUS_PAGE = 1, ++ PVSCSI_MEM_SPACE_MISC_PAGE = 2, ++ PVSCSI_MEM_SPACE_KICK_IO_PAGE = 4, ++ PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE = 6, ++ PVSCSI_MEM_SPACE_MSIX_PBA_PAGE = 7, ++}; ++ ++#define PVSCSI_MEM_SPACE_NUM_PAGES \ ++ (PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES + \ ++ PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES + \ ++ PVSCSI_MEM_SPACE_MISC_NUM_PAGES + \ ++ PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES + \ ++ PVSCSI_MEM_SPACE_MSIX_NUM_PAGES) ++ ++#define PVSCSI_MEM_SPACE_SIZE (PVSCSI_MEM_SPACE_NUM_PAGES * PAGE_SIZE) ++ ++#endif /* _VMW_PVSCSI_H_ */ diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index eadc1ab..2d81457 100644 --- a/drivers/serial/kgdboc.c @@ -48256,7 +65997,7 @@ index a5bf577..6d19845 100644 return hit; } diff --git a/fs/compat.c b/fs/compat.c -index d1e2411..c2ef8ed 100644 +index d1e2411..9a958d2 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -133,8 +133,8 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _ @@ -48377,18 +66118,7 @@ index d1e2411..c2ef8ed 100644 goto out; if (!file->f_op) goto out; -@@ -1454,6 +1472,10 @@ out: - return ret; - } - -+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+extern atomic64_unchecked_t global_exec_counter; -+#endif -+ - /* - * compat_do_execve() is mostly a copy of do_execve(), with the exception - * that it processes 32 bit argv and envp pointers. -@@ -1463,11 +1485,35 @@ int compat_do_execve(char * filename, +@@ -1463,11 +1481,35 @@ int compat_do_execve(char * filename, compat_uptr_t __user *envp, struct pt_regs * regs) { @@ -48424,7 +66154,7 @@ index d1e2411..c2ef8ed 100644 retval = unshare_files(&displaced); if (retval) -@@ -1493,12 +1539,26 @@ int compat_do_execve(char * filename, +@@ -1493,12 +1535,26 @@ int compat_do_execve(char * filename, if (IS_ERR(file)) goto out_unmark; @@ -48451,24 +66181,10 @@ index d1e2411..c2ef8ed 100644 retval = bprm_mm_init(bprm); if (retval) goto out_file; -@@ -1528,11 +1588,45 @@ int compat_do_execve(char * filename, +@@ -1515,24 +1571,63 @@ int compat_do_execve(char * filename, if (retval < 0) goto out; -+ if (!gr_tpe_allow(file)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ if (gr_check_crash_exec(file)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); -+ -+ gr_handle_exec_args_compat(bprm, argv); -+ +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim)); @@ -48476,12 +66192,49 @@ index d1e2411..c2ef8ed 100644 + get_file(file); + current->exec_file = file; +#endif ++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP ++ /* limit suid stack to 8MB ++ we saved the old limits above and will restore them if this exec fails ++ */ ++ if ((bprm->cred->euid != current_euid()) || (bprm->cred->egid != current_egid())) ++ current->signal->rlim[RLIMIT_STACK].rlim_cur = 8 * 1024 * 1024; ++#endif ++ ++ if (!gr_tpe_allow(file)) { ++ retval = -EACCES; ++ goto out_fail; ++ } ++ ++ if (gr_check_crash_exec(file)) { ++ retval = -EACCES; ++ goto out_fail; ++ } + + retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt, + bprm->unsafe); + if (retval < 0) + goto out_fail; + + retval = copy_strings_kernel(1, &bprm->filename, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; + + bprm->exec = bprm->p; + retval = compat_copy_strings(bprm->envc, envp, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; + + retval = compat_copy_strings(bprm->argc, argv, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; ++ ++ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); ++ ++ gr_handle_exec_args_compat(bprm, argv); + retval = search_binary_handler(bprm, regs); if (retval < 0) - goto out; @@ -48492,13 +66245,11 @@ index d1e2411..c2ef8ed 100644 +#endif /* execve succeeded */ -+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+ current->exec_id = atomic64_inc_return_unchecked(&global_exec_counter); -+#endif ++ increment_exec_counter(); current->fs->in_exec = 0; current->in_execve = 0; acct_update_integrals(current); -@@ -1541,6 +1635,14 @@ int compat_do_execve(char * filename, +@@ -1541,6 +1636,14 @@ int compat_do_execve(char * filename, put_files_struct(displaced); return retval; @@ -48513,7 +66264,7 @@ index d1e2411..c2ef8ed 100644 out: if (bprm->mm) { acct_arg_size(bprm, 0); -@@ -1711,6 +1813,8 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp, +@@ -1711,6 +1814,8 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp, struct fdtable *fdt; long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; @@ -48522,7 +66273,7 @@ index d1e2411..c2ef8ed 100644 if (n < 0) goto out_nofds; -@@ -2151,7 +2255,7 @@ asmlinkage long compat_sys_nfsservctl(int cmd, +@@ -2151,7 +2256,7 @@ asmlinkage long compat_sys_nfsservctl(int cmd, oldfs = get_fs(); set_fs(KERNEL_DS); /* The __user pointer casts are valid because of the set_fs() */ @@ -48871,7 +66622,7 @@ index 4434e8f..fa05803 100644 } mutex_unlock(&crypt_stat->cs_mutex); diff --git a/fs/exec.c b/fs/exec.c -index 86fafc6..6272c0e 100644 +index 86fafc6..6a041a8 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -56,12 +56,28 @@ @@ -48930,11 +66681,11 @@ index 86fafc6..6272c0e 100644 return page; +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+ // only allow 1MB for argv+env on suid/sgid binaries ++ // only allow 512KB for argv+env on suid/sgid binaries + // to prevent easy ASLR exhaustion + if (((bprm->cred->euid != current_euid()) || + (bprm->cred->egid != current_egid())) && -+ (size > (1024 * 1024))) { ++ (size > (512 * 1024))) { + put_page(page); + return NULL; + } @@ -48962,7 +66713,7 @@ index 86fafc6..6272c0e 100644 + +#ifdef CONFIG_PAX_RANDUSTACK + if (randomize_va_space) -+ bprm->p ^= (pax_get_random_long() & ~15) & ~PAGE_MASK; ++ bprm->p ^= random32() & ~PAGE_MASK; +#endif + return 0; @@ -49135,18 +66886,29 @@ index 86fafc6..6272c0e 100644 bprm->unsafe |= LSM_UNSAFE_SHARE; } else { res = -EAGAIN; -@@ -1339,6 +1384,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) +@@ -1339,6 +1384,21 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) EXPORT_SYMBOL(search_binary_handler); +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+atomic64_unchecked_t global_exec_counter = ATOMIC64_INIT(0); ++DEFINE_PER_CPU(u64, exec_counter); ++static int __init init_exec_counters(void) ++{ ++ unsigned int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ per_cpu(exec_counter, cpu) = (u64)cpu; ++ } ++ ++ return 0; ++} ++early_initcall(init_exec_counters); +#endif + /* * sys_execve() executes a new program. */ -@@ -1347,11 +1396,35 @@ int do_execve(char * filename, +@@ -1347,11 +1407,35 @@ int do_execve(char * filename, char __user *__user *envp, struct pt_regs * regs) { @@ -49182,7 +66944,7 @@ index 86fafc6..6272c0e 100644 retval = unshare_files(&displaced); if (retval) -@@ -1377,12 +1450,27 @@ int do_execve(char * filename, +@@ -1377,12 +1461,27 @@ int do_execve(char * filename, if (IS_ERR(file)) goto out_unmark; @@ -49210,24 +66972,10 @@ index 86fafc6..6272c0e 100644 retval = bprm_mm_init(bprm); if (retval) goto out_file; -@@ -1412,12 +1500,47 @@ int do_execve(char * filename, +@@ -1399,25 +1498,66 @@ int do_execve(char * filename, if (retval < 0) goto out; -+ if (!gr_tpe_allow(file)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ if (gr_check_crash_exec(file)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); -+ -+ gr_handle_exec_args(bprm, (const char __user *const __user *)argv); -+ +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim)); @@ -49235,12 +66983,50 @@ index 86fafc6..6272c0e 100644 + get_file(file); + current->exec_file = file; +#endif ++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP ++ /* limit suid stack to 8MB ++ we saved the old limits above and will restore them if this exec fails ++ */ ++ if (((bprm->cred->euid != current_euid()) || (bprm->cred->egid != current_egid())) && ++ (old_rlim[RLIMIT_STACK].rlim_cur > (8 * 1024 * 1024))) ++ current->signal->rlim[RLIMIT_STACK].rlim_cur = 8 * 1024 * 1024; ++#endif ++ ++ if (!gr_tpe_allow(file)) { ++ retval = -EACCES; ++ goto out_fail; ++ } ++ ++ if (gr_check_crash_exec(file)) { ++ retval = -EACCES; ++ goto out_fail; ++ } + + retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt, + bprm->unsafe); + if (retval < 0) + goto out_fail; + + retval = copy_strings_kernel(1, &bprm->filename, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; + + bprm->exec = bprm->p; + retval = copy_strings(bprm->envc, envp, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; + + retval = copy_strings(bprm->argc, argv, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; ++ ++ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); ++ ++ gr_handle_exec_args(bprm, (const char __user *const __user *)argv); + current->flags &= ~PF_KTHREAD; retval = search_binary_handler(bprm,regs); if (retval < 0) @@ -49252,14 +67038,12 @@ index 86fafc6..6272c0e 100644 +#endif /* execve succeeded */ -+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+ current->exec_id = atomic64_inc_return_unchecked(&global_exec_counter); -+#endif + ++ increment_exec_counter(); current->fs->in_exec = 0; current->in_execve = 0; acct_update_integrals(current); -@@ -1426,6 +1549,14 @@ int do_execve(char * filename, +@@ -1426,6 +1566,14 @@ int do_execve(char * filename, put_files_struct(displaced); return retval; @@ -49274,7 +67058,7 @@ index 86fafc6..6272c0e 100644 out: if (bprm->mm) { acct_arg_size(bprm, 0); -@@ -1591,6 +1722,220 @@ out: +@@ -1591,6 +1739,219 @@ out: return ispipe; } @@ -49465,8 +67249,7 @@ index 86fafc6..6272c0e 100644 +#endif +} + -+ -+NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) ++__noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) +{ + if (current->signal->curr_ip) + printk(KERN_ERR "PAX: From %pI4: kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n", @@ -49495,7 +67278,7 @@ index 86fafc6..6272c0e 100644 static int zap_process(struct task_struct *start) { struct task_struct *t; -@@ -1793,17 +2138,17 @@ static void wait_for_dump_helpers(struct file *file) +@@ -1793,17 +2154,17 @@ static void wait_for_dump_helpers(struct file *file) pipe = file->f_path.dentry->d_inode->i_pipe; pipe_lock(pipe); @@ -49518,7 +67301,7 @@ index 86fafc6..6272c0e 100644 pipe_unlock(pipe); } -@@ -1826,10 +2171,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -1826,10 +2187,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) char **helper_argv = NULL; int helper_argc = 0; int dump_count = 0; @@ -49533,7 +67316,7 @@ index 86fafc6..6272c0e 100644 binfmt = mm->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; -@@ -1874,6 +2222,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -1874,6 +2238,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) */ clear_thread_flag(TIF_SIGPENDING); @@ -49542,7 +67325,7 @@ index 86fafc6..6272c0e 100644 /* * lock_kernel() because format_corename() is controlled by sysctl, which * uses lock_kernel() -@@ -1908,7 +2258,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -1908,7 +2274,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) goto fail_unlock; } @@ -49551,7 +67334,7 @@ index 86fafc6..6272c0e 100644 if (core_pipe_limit && (core_pipe_limit < dump_count)) { printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", task_tgid_vnr(current), current->comm); -@@ -1972,7 +2322,7 @@ close_fail: +@@ -1972,7 +2338,7 @@ close_fail: filp_close(file, NULL); fail_dropcount: if (dump_count) @@ -55467,10 +73250,10 @@ index 8f32f50..b6a41e8 100644 link[pathlen] = '\0'; diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig new file mode 100644 -index 0000000..7026cbd +index 0000000..50819f8 --- /dev/null +++ b/grsecurity/Kconfig -@@ -0,0 +1,1074 @@ +@@ -0,0 +1,1077 @@ +# +# grecurity configuration +# @@ -55745,11 +73528,13 @@ index 0000000..7026cbd + dangerous sources of information, this option causes reads of sensitive + /proc/<pid> entries where the file descriptor was opened in a different + task than the one performing the read. Such attempts are logged. -+ Finally, this option limits argv/env strings for suid/sgid binaries -+ to 1MB to prevent a complete exhaustion of the stack entropy provided -+ by ASLR. ++ This option also limits argv/env strings for suid/sgid binaries ++ to 512KB to prevent a complete exhaustion of the stack entropy provided ++ by ASLR. Finally, it places an 8MB stack resource limit on suid/sgid ++ binaries to prevent alternative mmap layouts from being abused. ++ + If you use PaX it is essential that you say Y here as it closes up -+ several holes that make full ASLR useless for suid/sgid binaries. ++ several holes that make full ASLR useless locally. + +config GRKERNSEC_BRUTE + bool "Deter exploit bruteforcing" @@ -55888,8 +73673,9 @@ index 0000000..7026cbd + Depending upon the option you choose, you can either restrict users to + see only the processes they themselves run, or choose a group that can + view all processes and files normally restricted to root if you choose -+ the "restrict to user only" option. NOTE: If you're running identd as -+ a non-root user, you will have to run it as the group you specify here. ++ the "restrict to user only" option. NOTE: If you're running identd or ++ ntpd as a non-root user, you will have to run it as the group you ++ specify here. + +config GRKERNSEC_PROC_USER + bool "Restrict /proc to user only" @@ -69115,6 +86901,18 @@ index 81c9689..a567a55 100644 /* * Protect attach/detach and child_list: +diff --git a/include/linux/personality.h b/include/linux/personality.h +index 1261208..ddef96f 100644 +--- a/include/linux/personality.h ++++ b/include/linux/personality.h +@@ -43,6 +43,7 @@ enum { + #define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC | \ + ADDR_NO_RANDOMIZE | \ + ADDR_COMPAT_LAYOUT | \ ++ ADDR_LIMIT_3GB | \ + MMAP_PAGE_ZERO) + + /* diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index b43a9e0..b77d869 100644 --- a/include/linux/pipe_fs_i.h @@ -69174,6 +86972,18 @@ index 72b1a10..13303a9 100644 /** * preempt_notifier - key for installing preemption notifiers +diff --git a/include/linux/prefetch.h b/include/linux/prefetch.h +index af7c36a..a93005c 100644 +--- a/include/linux/prefetch.h ++++ b/include/linux/prefetch.h +@@ -11,6 +11,7 @@ + #define _LINUX_PREFETCH_H + + #include <linux/types.h> ++#include <linux/const.h> + #include <asm/processor.h> + #include <asm/cache.h> + diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 379eaed..1bf73e3 100644 --- a/include/linux/proc_fs.h @@ -69392,7 +87202,7 @@ index 3392c59..a746428 100644 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /** diff --git a/include/linux/sched.h b/include/linux/sched.h -index 71849bf..2ef383dc3 100644 +index 71849bf..8cf9dd2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -101,6 +101,7 @@ struct bio; @@ -69594,7 +87404,7 @@ index 71849bf..2ef383dc3 100644 +extern void pax_report_fault(struct pt_regs *regs, void *pc, void *sp); +extern void pax_report_insns(struct pt_regs *regs, void *pc, void *sp); +extern void pax_report_refcount_overflow(struct pt_regs *regs); -+extern NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) ATTRIB_NORET; ++extern __noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type); + +#ifdef CONFIG_PAX_MEMORY_STACKLEAK +extern void pax_track_stack(void); @@ -69637,7 +87447,7 @@ index 71849bf..2ef383dc3 100644 extern void flush_itimer_signals(void); -extern NORET_TYPE void do_group_exit(int); -+extern NORET_TYPE void do_group_exit(int) ATTRIB_NORET; ++extern __noreturn void do_group_exit(int); extern void daemonize(const char *, ...); extern int allow_signal(int); @@ -69661,6 +87471,30 @@ index 71849bf..2ef383dc3 100644 extern void thread_info_cache_init(void); #ifdef CONFIG_DEBUG_STACK_USAGE +@@ -2616,6 +2720,23 @@ static inline unsigned long rlimit_max(unsigned int limit) + return task_rlimit_max(current, limit); + } + ++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP ++DECLARE_PER_CPU(u64, exec_counter); ++static inline void increment_exec_counter(void) ++{ ++ unsigned int cpu; ++ u64 *exec_id_ptr; ++ BUILD_BUG_ON(NR_CPUS > (1 << 16)); ++ cpu = get_cpu(); ++ exec_id_ptr = &per_cpu(exec_counter, cpu); ++ *exec_id_ptr += 1ULL << 16; ++ current->exec_id = *exec_id_ptr; ++ put_cpu(); ++} ++#else ++static inline void increment_exec_counter(void) {} ++#endif ++ + #endif /* __KERNEL__ */ + + #endif diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h index 1ee2c05..81b7ec4 100644 --- a/include/linux/screen_info.h @@ -69772,7 +87606,7 @@ index eca6235..c7417ed 100644 /* shm_mode upper byte flags */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h -index bcdd660..6e12e11 100644 +index bcdd660..fd2e332 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -14,6 +14,7 @@ @@ -69819,6 +87653,29 @@ index bcdd660..6e12e11 100644 #endif extern int ___pskb_trim(struct sk_buff *skb, unsigned int len); +@@ -1489,6 +1490,22 @@ static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, + return __netdev_alloc_skb(dev, length, GFP_ATOMIC); + } + ++static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++ ++static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length) ++{ ++ return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC); ++} ++ + extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask); + + /** diff --git a/include/linux/slab.h b/include/linux/slab.h index 2da8372..a3be824 100644 --- a/include/linux/slab.h @@ -71002,6 +88859,23 @@ index de8e180..f15e0d7 100644 struct device sdev_gendev, sdev_dev; +diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h +index 0b4baba..0106e9e 100644 +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -43,6 +43,12 @@ struct blk_queue_tags; + #define DISABLE_CLUSTERING 0 + #define ENABLE_CLUSTERING 1 + ++enum { ++ SCSI_QDEPTH_DEFAULT, /* default requested change, e.g. from sysfs */ ++ SCSI_QDEPTH_QFULL, /* scsi-ml requested due to queue full */ ++ SCSI_QDEPTH_RAMP_UP, /* scsi-ml requested due to threshhold event */ ++}; ++ + struct scsi_host_template { + struct module *module; + const char *name; diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index fc50bd6..81ba9cb 100644 --- a/include/scsi/scsi_transport_fc.h @@ -72479,7 +90353,7 @@ index 0b5b5fc..f7fe51a 100644 if (ret < 0) return ret; diff --git a/kernel/exit.c b/kernel/exit.c -index 0f8fae3..7916abf 100644 +index 0f8fae3..66af9b1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -55,6 +55,10 @@ @@ -72589,6 +90463,15 @@ index 0f8fae3..7916abf 100644 if (tsk->splice_pipe) __free_pipe_info(tsk->splice_pipe); +@@ -1059,7 +1088,7 @@ SYSCALL_DEFINE1(exit, int, error_code) + * Take down every thread in the group. This is called by fatal signals + * as well as by sys_exit_group (below). + */ +-NORET_TYPE void ++__noreturn void + do_group_exit(int exit_code) + { + struct signal_struct *sig = current->signal; @@ -1188,7 +1217,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) if (unlikely(wo->wo_flags & WNOWAIT)) { @@ -73405,7 +91288,7 @@ index d4aba4f..02a353f 100644 if (!name) { diff --git a/kernel/module.c b/kernel/module.c -index 4b270e6..2226274 100644 +index 4b270e6..2efdb65 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -55,6 +55,7 @@ @@ -73736,7 +91619,7 @@ index 4b270e6..2226274 100644 + license = get_modinfo(sechdrs, infoindex, "license"); +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + if (!license || !license_is_gpl_compatible(license)) { -+ err -ENOEXEC; ++ err = -ENOEXEC; + goto free_hdr; + } +#endif @@ -82899,6 +100782,19 @@ index 9cc6289..052c521 100644 } int udp6_seq_show(struct seq_file *seq, void *v) +diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c +index 48bb1e3..5980e6e 100644 +--- a/net/ipv6/xfrm6_tunnel.c ++++ b/net/ipv6/xfrm6_tunnel.c +@@ -258,7 +258,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb) + __be32 spi; + + spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); +- return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; ++ return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi); + } + + static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 811984d..11f59b7 100644 --- a/net/irda/ircomm/ircomm_tty.c @@ -85334,7 +103230,7 @@ index d52f7a0..269eb1b 100755 rm -f tags xtags ctags diff --git a/security/Kconfig b/security/Kconfig -index fb363cd..886ace4 100644 +index fb363cd..90fc8f4 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -4,6 +4,626 @@ @@ -85910,7 +103806,7 @@ index fb363cd..886ace4 100644 + +config PAX_REFCOUNT + bool "Prevent various kernel object reference counter overflows" -+ depends on GRKERNSEC && (X86 || SPARC64) ++ depends on GRKERNSEC && ((ARM && (CPU_32v6 || CPU_32v6K || CPU_32v7)) || SPARC64 || X86) + help + By saying Y here the kernel will detect and prevent overflowing + various (but not all) kinds of object reference counters. Such @@ -87245,10 +105141,10 @@ index 79633ea..9732e90 100644 } diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile new file mode 100644 -index 0000000..469b06a +index 0000000..894c8bf --- /dev/null +++ b/tools/gcc/Makefile -@@ -0,0 +1,21 @@ +@@ -0,0 +1,23 @@ +#CC := gcc +#PLUGIN_SOURCE_FILES := pax_plugin.c +#PLUGIN_OBJECT_FILES := $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES)) @@ -87262,6 +105158,7 @@ index 0000000..469b06a +hostlibs-$(CONFIG_KALLOCSTAT_PLUGIN) += kallocstat_plugin.so +hostlibs-$(CONFIG_PAX_KERNEXEC_PLUGIN) += kernexec_plugin.so +hostlibs-$(CONFIG_CHECKER_PLUGIN) += checker_plugin.so ++hostlibs-y += colorize_plugin.so + +always := $(hostlibs-y) + @@ -87270,6 +105167,7 @@ index 0000000..469b06a +kallocstat_plugin-objs := kallocstat_plugin.o +kernexec_plugin-objs := kernexec_plugin.o +checker_plugin-objs := checker_plugin.o ++colorize_plugin-objs := colorize_plugin.o diff --git a/tools/gcc/checker_plugin.c b/tools/gcc/checker_plugin.c new file mode 100644 index 0000000..d41b5af @@ -87447,6 +105345,159 @@ index 0000000..d41b5af + + return 0; +} +diff --git a/tools/gcc/colorize_plugin.c b/tools/gcc/colorize_plugin.c +new file mode 100644 +index 0000000..ee950d0 +--- /dev/null ++++ b/tools/gcc/colorize_plugin.c +@@ -0,0 +1,147 @@ ++/* ++ * Copyright 2012 by PaX Team <pageexec@freemail.hu> ++ * Licensed under the GPL v2 ++ * ++ * Note: the choice of the license means that the compilation process is ++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, ++ * but for the kernel it doesn't matter since it doesn't link against ++ * any of the gcc libraries ++ * ++ * gcc plugin to colorize diagnostic output ++ * ++ */ ++ ++#include "gcc-plugin.h" ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tree.h" ++#include "tree-pass.h" ++#include "flags.h" ++#include "intl.h" ++#include "toplev.h" ++#include "plugin.h" ++#include "diagnostic.h" ++#include "plugin-version.h" ++#include "tm.h" ++ ++int plugin_is_GPL_compatible; ++ ++static struct plugin_info colorize_plugin_info = { ++ .version = "201203092200", ++}; ++ ++#define GREEN "\033[32m\033[2m" ++#define LIGHTGREEN "\033[32m\033[1m" ++#define YELLOW "\033[33m\033[2m" ++#define LIGHTYELLOW "\033[33m\033[1m" ++#define RED "\033[31m\033[2m" ++#define LIGHTRED "\033[31m\033[1m" ++#define BLUE "\033[34m\033[2m" ++#define LIGHTBLUE "\033[34m\033[1m" ++#define BRIGHT "\033[m\033[1m" ++#define NORMAL "\033[m" ++ ++static diagnostic_starter_fn old_starter; ++static diagnostic_finalizer_fn old_finalizer; ++ ++static void start_colorize(diagnostic_context *context, diagnostic_info *diagnostic) ++{ ++ const char *color; ++ char *newprefix; ++ ++ switch (diagnostic->kind) { ++ case DK_NOTE: ++ color = LIGHTBLUE; ++ break; ++ ++ case DK_PEDWARN: ++ case DK_WARNING: ++ color = LIGHTYELLOW; ++ break; ++ ++ case DK_ERROR: ++ case DK_FATAL: ++ case DK_ICE: ++ case DK_PERMERROR: ++ case DK_SORRY: ++ color = LIGHTRED; ++ break; ++ ++ default: ++ color = NORMAL; ++ } ++ ++ old_starter(context, diagnostic); ++ if (-1 == asprintf(&newprefix, "%s%s" NORMAL, color, context->printer->prefix)) ++ return; ++ pp_destroy_prefix(context->printer); ++ pp_set_prefix(context->printer, newprefix); ++} ++ ++static void finalize_colorize(diagnostic_context *context, diagnostic_info *diagnostic) ++{ ++ old_finalizer(context, diagnostic); ++} ++ ++static void colorize_arm(void) ++{ ++ old_starter = diagnostic_starter(global_dc); ++ old_finalizer = diagnostic_finalizer(global_dc); ++ ++ diagnostic_starter(global_dc) = start_colorize; ++ diagnostic_finalizer(global_dc) = finalize_colorize; ++} ++ ++static unsigned int execute_colorize_rearm(void) ++{ ++ if (diagnostic_starter(global_dc) == start_colorize) ++ return 0; ++ ++ colorize_arm(); ++ return 0; ++} ++ ++struct simple_ipa_opt_pass pass_ipa_colorize_rearm = { ++ .pass = { ++ .type = SIMPLE_IPA_PASS, ++ .name = "colorize_rearm", ++ .gate = NULL, ++ .execute = execute_colorize_rearm, ++ .sub = NULL, ++ .next = NULL, ++ .static_pass_number = 0, ++ .tv_id = TV_NONE, ++ .properties_required = 0, ++ .properties_provided = 0, ++ .properties_destroyed = 0, ++ .todo_flags_start = 0, ++ .todo_flags_finish = 0 ++ } ++}; ++ ++static void colorize_start_unit(void *gcc_data, void *user_data) ++{ ++ colorize_arm(); ++} ++ ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ const char * const plugin_name = plugin_info->base_name; ++ struct register_pass_info colorize_rearm_pass_info = { ++ .pass = &pass_ipa_colorize_rearm.pass, ++ .reference_pass_name = "*free_lang_data", ++ .ref_pass_instance_number = 0, ++ .pos_op = PASS_POS_INSERT_AFTER ++ }; ++ ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; ++ } ++ ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &colorize_plugin_info); ++ register_callback(plugin_name, PLUGIN_START_UNIT, &colorize_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &colorize_rearm_pass_info); ++ return 0; ++} diff --git a/tools/gcc/constify_plugin.c b/tools/gcc/constify_plugin.c new file mode 100644 index 0000000..704a564 @@ -88364,7 +106415,7 @@ index 0000000..008f159 +} diff --git a/tools/gcc/stackleak_plugin.c b/tools/gcc/stackleak_plugin.c new file mode 100644 -index 0000000..4a9b187 +index 0000000..ea79948 --- /dev/null +++ b/tools/gcc/stackleak_plugin.c @@ -0,0 +1,326 @@ @@ -88618,7 +106669,7 @@ index 0000000..4a9b187 + return 0; +} + -+static void stackleak_start_unit(void *gcc_data, void *user_dat) ++static void stackleak_start_unit(void *gcc_data, void *user_data) +{ + tree fntype; + @@ -88688,7 +106739,7 @@ index 0000000..4a9b187 + error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + } + -+ register_callback("start_unit", PLUGIN_START_UNIT, &stackleak_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_START_UNIT, &stackleak_start_unit, NULL); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_tree_instrument_pass_info); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_final_pass_info); + diff --git a/2.6.32/4445_grsec-pax-without-grsec.patch b/2.6.32/4445_grsec-pax-without-grsec.patch index 591a120..f07b2df 100644 --- a/2.6.32/4445_grsec-pax-without-grsec.patch +++ b/2.6.32/4445_grsec-pax-without-grsec.patch @@ -3,6 +3,9 @@ From: Anthony G. Basile <blueness@gentoo.org> With grsecurity-2.2.2-2.6.32.38-201104171745, the functions pax_report_leak_to_user and pax_report_overflow_from_user in fs/exec.c were consolidated into pax_report_usercopy. This patch has been updated to reflect that change. + +With grsecurity-2.9-2.6.32.58-201203131839, NORET_TYPE has been replaced by __noreturn. +This patch has been updated to reflect that change. -- From: Jory Pratt <anarchy@gentoo.org> Updated patch for kernel 2.6.32 @@ -36,7 +39,7 @@ diff -Naur a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c diff -Naur a/fs/exec.c b/fs/exec.c --- a/fs/exec.c 2011-04-17 18:15:55.000000000 -0400 +++ b/fs/exec.c 2011-04-17 18:29:40.000000000 -0400 -@@ -1832,9 +1832,11 @@ +@@ -1849,9 +1849,11 @@ } up_read(&mm->mmap_sem); } @@ -48,7 +51,7 @@ diff -Naur a/fs/exec.c b/fs/exec.c printk(KERN_ERR "PAX: execution attempt in: %s, %08lx-%08lx %08lx\n", path_fault, start, end, offset); printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, " "PC: %p, SP: %p\n", path_exec, tsk->comm, task_pid_nr(tsk), -@@ -1849,10 +1851,12 @@ +@@ -1866,10 +1868,12 @@ #ifdef CONFIG_PAX_REFCOUNT void pax_report_refcount_overflow(struct pt_regs *regs) { @@ -61,9 +64,9 @@ diff -Naur a/fs/exec.c b/fs/exec.c printk(KERN_ERR "PAX: refcount overflow detected in: %s:%d, uid/euid: %u/%u\n", current->comm, task_pid_nr(current), current_uid(), current_euid()); print_symbol(KERN_ERR "PAX: refcount overflow occured at: %s\n", instruction_pointer(regs)); -@@ -1912,10 +1916,12 @@ +@@ -1928,10 +1932,12 @@ - NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) + __noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) { +#ifdef CONFIG_GRKERNSEC if (current->signal->curr_ip) diff --git a/2.6.32/4450_grsec-kconfig-default-gids.patch b/2.6.32/4450_grsec-kconfig-default-gids.patch index 498adb6..8c6f609 100644 --- a/2.6.32/4450_grsec-kconfig-default-gids.patch +++ b/2.6.32/4450_grsec-kconfig-default-gids.patch @@ -12,7 +12,7 @@ from shooting themselves in the foot. diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig --- a/grsecurity/Kconfig 2011-12-12 15:11:47.000000000 -0500 +++ b/grsecurity/Kconfig 2011-12-12 15:13:17.000000000 -0500 -@@ -439,7 +439,7 @@ +@@ -442,7 +442,7 @@ config GRKERNSEC_PROC_GID int "GID for special group" depends on GRKERNSEC_PROC_USERGROUP @@ -21,7 +21,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig config GRKERNSEC_PROC_ADD bool "Additional restrictions" -@@ -667,7 +667,7 @@ +@@ -670,7 +670,7 @@ config GRKERNSEC_AUDIT_GID int "GID for auditing" depends on GRKERNSEC_AUDIT_GROUP @@ -30,7 +30,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig config GRKERNSEC_EXECLOG bool "Exec logging" -@@ -871,7 +871,7 @@ +@@ -874,7 +874,7 @@ config GRKERNSEC_TPE_GID int "GID for untrusted users" depends on GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT @@ -39,7 +39,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Setting this GID determines what group TPE restrictions will be *enabled* for. If the sysctl option is enabled, a sysctl option -@@ -880,7 +880,7 @@ +@@ -883,7 +883,7 @@ config GRKERNSEC_TPE_GID int "GID for trusted users" depends on GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT @@ -48,7 +48,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Setting this GID determines what group TPE restrictions will be *disabled* for. If the sysctl option is enabled, a sysctl option -@@ -953,7 +953,7 @@ +@@ -956,7 +956,7 @@ config GRKERNSEC_SOCKET_ALL_GID int "GID to deny all sockets for" depends on GRKERNSEC_SOCKET_ALL @@ -57,7 +57,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Here you can choose the GID to disable socket access for. Remember to add the users you want socket access disabled for to the GID -@@ -974,7 +974,7 @@ +@@ -977,7 +977,7 @@ config GRKERNSEC_SOCKET_CLIENT_GID int "GID to deny client sockets for" depends on GRKERNSEC_SOCKET_CLIENT @@ -66,7 +66,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Here you can choose the GID to disable client socket access for. Remember to add the users you want client socket access disabled for to -@@ -992,7 +992,7 @@ +@@ -995,7 +995,7 @@ config GRKERNSEC_SOCKET_SERVER_GID int "GID to deny server sockets for" depends on GRKERNSEC_SOCKET_SERVER diff --git a/2.6.32/4460-grsec-kconfig-proc-user.patch b/2.6.32/4460-grsec-kconfig-proc-user.patch index 1e181f3..b94ee69 100644 --- a/2.6.32/4460-grsec-kconfig-proc-user.patch +++ b/2.6.32/4460-grsec-kconfig-proc-user.patch @@ -6,7 +6,7 @@ in a different way to avoid bug #366019. This patch should eventually go upstre diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig --- a/grsecurity/Kconfig 2011-06-29 07:46:02.000000000 -0400 +++ b/grsecurity/Kconfig 2011-06-29 07:47:20.000000000 -0400 -@@ -673,7 +673,7 @@ +@@ -676,7 +676,7 @@ config GRKERNSEC_PROC_USER bool "Restrict /proc to user only" @@ -15,7 +15,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help If you say Y here, non-root users will only be able to view their own processes, and restricts them from viewing network-related information, -@@ -681,7 +681,7 @@ +@@ -684,7 +684,7 @@ config GRKERNSEC_PROC_USERGROUP bool "Allow special group" diff --git a/2.6.32/4465_selinux-avc_audit-log-curr_ip.patch b/2.6.32/4465_selinux-avc_audit-log-curr_ip.patch index fe2f190..11d9263 100644 --- a/2.6.32/4465_selinux-avc_audit-log-curr_ip.patch +++ b/2.6.32/4465_selinux-avc_audit-log-curr_ip.patch @@ -28,7 +28,7 @@ Signed-off-by: Lorenzo Hernandez Garcia-Hierro <lorenzo@gnu.org> diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig --- a/grsecurity/Kconfig 2011-04-17 18:47:02.000000000 -0400 +++ b/grsecurity/Kconfig 2011-04-17 18:51:15.000000000 -0400 -@@ -1302,6 +1302,27 @@ +@@ -1305,6 +1305,27 @@ menu "Logging Options" depends on GRKERNSEC diff --git a/3.2.9/0000_README b/3.2.11/0000_README index c6fa1e9..b641520 100644 --- a/3.2.9/0000_README +++ b/3.2.11/0000_README @@ -2,7 +2,7 @@ README ----------------------------------------------------------------------------- Individual Patch Descriptions: ----------------------------------------------------------------------------- -Patch: 4420_grsecurity-2.9-3.2.9-201203062051.patch +Patch: 4420_grsecurity-2.9-3.2.11-201203141956.patch From: http://www.grsecurity.net Desc: hardened-sources base patch from upstream grsecurity diff --git a/3.2.9/4420_grsecurity-2.9-3.2.9-201203062051.patch b/3.2.11/4420_grsecurity-2.9-3.2.11-201203141956.patch index 7a64df3..ba37ae4 100644 --- a/3.2.9/4420_grsecurity-2.9-3.2.9-201203062051.patch +++ b/3.2.11/4420_grsecurity-2.9-3.2.11-201203141956.patch @@ -1,5 +1,5 @@ diff --git a/Documentation/dontdiff b/Documentation/dontdiff -index dfa6fc6..0095943 100644 +index dfa6fc6..6af9546 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -5,6 +5,7 @@ @@ -63,7 +63,11 @@ index dfa6fc6..0095943 100644 conmakehash consolemap_deftbl.c* cpustr.h -@@ -119,6 +129,7 @@ dslm +@@ -116,9 +126,11 @@ devlist.h* + dnotify_test + docproc + dslm ++dtc-lexer.lex.c elf2ecoff elfconfig.h* evergreen_reg_safe.h @@ -71,7 +75,7 @@ index dfa6fc6..0095943 100644 fixdep flask.h fore200e_mkfirm -@@ -126,12 +137,15 @@ fore200e_pca_fw.c* +@@ -126,12 +138,15 @@ fore200e_pca_fw.c* gconf gconf.glade.h gen-devlist @@ -87,7 +91,7 @@ index dfa6fc6..0095943 100644 hpet_example hugepage-mmap hugepage-shm -@@ -146,7 +160,7 @@ int32.c +@@ -146,7 +161,7 @@ int32.c int4.c int8.c kallsyms @@ -96,15 +100,16 @@ index dfa6fc6..0095943 100644 keywords.c ksym.c* ksym.h* -@@ -154,7 +168,6 @@ kxgettext +@@ -154,7 +169,7 @@ kxgettext lkc_defs.h lex.c lex.*.c -linux ++lib1funcs.S logo_*.c logo_*_clut224.c logo_*_mono.c -@@ -166,14 +179,15 @@ machtypes.h +@@ -166,14 +181,15 @@ machtypes.h map map_hugetlb maui_boot.h @@ -121,7 +126,7 @@ index dfa6fc6..0095943 100644 mkprep mkregtable mktables -@@ -209,6 +223,7 @@ r300_reg_safe.h +@@ -209,6 +225,7 @@ r300_reg_safe.h r420_reg_safe.h r600_reg_safe.h recordmcount @@ -129,7 +134,7 @@ index dfa6fc6..0095943 100644 relocs rlim_names.h rn50_reg_safe.h -@@ -219,6 +234,7 @@ setup +@@ -219,6 +236,7 @@ setup setup.bin setup.elf sImage @@ -137,7 +142,7 @@ index dfa6fc6..0095943 100644 sm_tbl* split-include syscalltab.h -@@ -229,6 +245,7 @@ tftpboot.img +@@ -229,6 +247,7 @@ tftpboot.img timeconst.h times.h* trix_boot.h @@ -145,7 +150,7 @@ index dfa6fc6..0095943 100644 utsrelease.h* vdso-syms.lds vdso.lds -@@ -246,7 +263,9 @@ vmlinux +@@ -246,7 +265,9 @@ vmlinux vmlinux-* vmlinux.aout vmlinux.bin.all @@ -155,7 +160,7 @@ index dfa6fc6..0095943 100644 vmlinuz voffset.h vsyscall.lds -@@ -254,9 +273,11 @@ vsyscall_32.lds +@@ -254,9 +275,11 @@ vsyscall_32.lds wanxlfw.inc uImage unifdef @@ -186,7 +191,7 @@ index 81c287f..d456d02 100644 pcd. [PARIDE] diff --git a/Makefile b/Makefile -index 5f1739b..1831396 100644 +index 4b76371..53aa79c 100644 --- a/Makefile +++ b/Makefile @@ -245,8 +245,9 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ @@ -212,7 +217,7 @@ index 5f1739b..1831396 100644 $(Q)$(MAKE) $(build)=scripts/basic $(Q)rm -f .tmp_quiet_recordmcount -@@ -564,6 +565,48 @@ else +@@ -564,6 +565,50 @@ else KBUILD_CFLAGS += -O2 endif @@ -238,7 +243,9 @@ index 5f1739b..1831396 100644 +CHECKER_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/checker_plugin.so -DCHECKER_PLUGIN +endif +endif -+GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS) $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS) ++COLORIZE_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/colorize_plugin.so ++GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS) ++GCC_PLUGINS_CFLAGS += $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS) $(COLORIZE_PLUGIN_CFLAGS) +GCC_PLUGINS_AFLAGS := $(KERNEXEC_PLUGIN_AFLAGS) +export CONSTIFY_PLUGIN STACKLEAK_PLUGIN KERNEXEC_PLUGIN CHECKER_PLUGIN +ifeq ($(KBUILD_EXTMOD),) @@ -261,7 +268,7 @@ index 5f1739b..1831396 100644 include $(srctree)/arch/$(SRCARCH)/Makefile ifneq ($(CONFIG_FRAME_WARN),0) -@@ -708,7 +751,7 @@ export mod_strip_cmd +@@ -708,7 +753,7 @@ export mod_strip_cmd ifeq ($(KBUILD_EXTMOD),) @@ -270,7 +277,7 @@ index 5f1739b..1831396 100644 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ -@@ -932,6 +975,8 @@ vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE +@@ -932,6 +977,8 @@ vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE # The actual objects are generated when descending, # make sure no implicit rule kicks in @@ -279,7 +286,7 @@ index 5f1739b..1831396 100644 $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; # Handle descending into subdirectories listed in $(vmlinux-dirs) -@@ -941,7 +986,7 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; +@@ -941,7 +988,7 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; # Error messages still appears in the original language PHONY += $(vmlinux-dirs) @@ -288,7 +295,7 @@ index 5f1739b..1831396 100644 $(Q)$(MAKE) $(build)=$@ # Store (new) KERNELRELASE string in include/config/kernel.release -@@ -985,6 +1030,7 @@ prepare0: archprepare FORCE +@@ -985,6 +1032,7 @@ prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. # All the preparing.. @@ -296,7 +303,7 @@ index 5f1739b..1831396 100644 prepare: prepare0 # Generate some files -@@ -1086,6 +1132,8 @@ all: modules +@@ -1086,6 +1134,8 @@ all: modules # using awk while concatenating to the final file. PHONY += modules @@ -305,7 +312,7 @@ index 5f1739b..1831396 100644 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order @$(kecho) ' Building modules, stage 2.'; -@@ -1101,7 +1149,7 @@ modules.builtin: $(vmlinux-dirs:%=%/modules.builtin) +@@ -1101,7 +1151,7 @@ modules.builtin: $(vmlinux-dirs:%=%/modules.builtin) # Target to prepare building external modules PHONY += modules_prepare @@ -314,7 +321,7 @@ index 5f1739b..1831396 100644 # Target to install modules PHONY += modules_install -@@ -1198,6 +1246,7 @@ distclean: mrproper +@@ -1198,6 +1248,7 @@ distclean: mrproper \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ -o -name '.*.rej' \ @@ -322,7 +329,7 @@ index 5f1739b..1831396 100644 -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ -type f -print | xargs rm -f -@@ -1358,6 +1407,8 @@ PHONY += $(module-dirs) modules +@@ -1358,6 +1409,8 @@ PHONY += $(module-dirs) modules $(module-dirs): crmodverdir $(objtree)/Module.symvers $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) @@ -331,7 +338,7 @@ index 5f1739b..1831396 100644 modules: $(module-dirs) @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost -@@ -1484,17 +1535,21 @@ else +@@ -1484,17 +1537,21 @@ else target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) endif @@ -357,7 +364,7 @@ index 5f1739b..1831396 100644 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) %.symtypes: %.c prepare scripts FORCE $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -@@ -1504,11 +1559,15 @@ endif +@@ -1504,11 +1561,15 @@ endif $(cmd_crmodverdir) $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ $(build)=$(build-dir) @@ -396,6 +403,32 @@ index 640f909..48b6597 100644 #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() #define smp_mb__before_atomic_inc() smp_mb() +diff --git a/arch/alpha/include/asm/cache.h b/arch/alpha/include/asm/cache.h +index ad368a9..fbe0f25 100644 +--- a/arch/alpha/include/asm/cache.h ++++ b/arch/alpha/include/asm/cache.h +@@ -4,19 +4,19 @@ + #ifndef __ARCH_ALPHA_CACHE_H + #define __ARCH_ALPHA_CACHE_H + ++#include <linux/const.h> + + /* Bytes per L1 (data) cache line. */ + #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6) +-# define L1_CACHE_BYTES 64 + # define L1_CACHE_SHIFT 6 + #else + /* Both EV4 and EV5 are write-through, read-allocate, + direct-mapped, physical. + */ +-# define L1_CACHE_BYTES 32 + # define L1_CACHE_SHIFT 5 + #endif + ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + #define SMP_CACHE_BYTES L1_CACHE_BYTES + + #endif diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h index da5449e..7418343 100644 --- a/arch/alpha/include/asm/elf.h @@ -645,7 +678,7 @@ index fadd5f8..904e73a 100644 /* Allow reads even for write-only mappings */ if (!(vma->vm_flags & (VM_READ | VM_WRITE))) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h -index 86976d0..6610950 100644 +index 86976d0..683de93 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -15,6 +15,10 @@ @@ -659,7 +692,234 @@ index 86976d0..6610950 100644 #define ATOMIC_INIT(i) { (i) } #ifdef __KERNEL__ -@@ -239,6 +243,14 @@ typedef struct { +@@ -25,7 +29,15 @@ + * atomic_set() is the clrex or dummy strex done on every exception return. + */ + #define atomic_read(v) (*(volatile int *)&(v)->counter) ++static inline int atomic_read_unchecked(const atomic_unchecked_t *v) ++{ ++ return v->counter; ++} + #define atomic_set(v,i) (((v)->counter) = (i)) ++static inline void atomic_set_unchecked(atomic_unchecked_t *v, int i) ++{ ++ v->counter = i; ++} + + #if __LINUX_ARM_ARCH__ >= 6 + +@@ -40,6 +52,35 @@ static inline void atomic_add(int i, atomic_t *v) + int result; + + __asm__ __volatile__("@ atomic_add\n" ++"1: ldrex %1, [%3]\n" ++" adds %0, %1, %4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strex %1, %0, [%3]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "Ir" (i) ++ : "cc"); ++} ++ ++static inline void atomic_add_unchecked(int i, atomic_unchecked_t *v) ++{ ++ unsigned long tmp; ++ int result; ++ ++ __asm__ __volatile__("@ atomic_add_unchecked\n" + "1: ldrex %0, [%3]\n" + " add %0, %0, %4\n" + " strex %1, %0, [%3]\n" +@@ -58,6 +99,42 @@ static inline int atomic_add_return(int i, atomic_t *v) + smp_mb(); + + __asm__ __volatile__("@ atomic_add_return\n" ++"1: ldrex %1, [%3]\n" ++" adds %0, %1, %4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strex %1, %0, [%3]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "Ir" (i) ++ : "cc"); ++ ++ smp_mb(); ++ ++ return result; ++} ++ ++static inline int atomic_add_return_unchecked(int i, atomic_unchecked_t *v) ++{ ++ unsigned long tmp; ++ int result; ++ ++ smp_mb(); ++ ++ __asm__ __volatile__("@ atomic_add_return_unchecked\n" + "1: ldrex %0, [%3]\n" + " add %0, %0, %4\n" + " strex %1, %0, [%3]\n" +@@ -78,6 +155,35 @@ static inline void atomic_sub(int i, atomic_t *v) + int result; + + __asm__ __volatile__("@ atomic_sub\n" ++"1: ldrex %1, [%3]\n" ++" subs %0, %1, %4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strex %1, %0, [%3]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "Ir" (i) ++ : "cc"); ++} ++ ++static inline void atomic_sub_unchecked(int i, atomic_unchecked_t *v) ++{ ++ unsigned long tmp; ++ int result; ++ ++ __asm__ __volatile__("@ atomic_sub_unchecked\n" + "1: ldrex %0, [%3]\n" + " sub %0, %0, %4\n" + " strex %1, %0, [%3]\n" +@@ -96,11 +202,25 @@ static inline int atomic_sub_return(int i, atomic_t *v) + smp_mb(); + + __asm__ __volatile__("@ atomic_sub_return\n" +-"1: ldrex %0, [%3]\n" +-" sub %0, %0, %4\n" ++"1: ldrex %1, [%3]\n" ++" sub %0, %1, %4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ + " strex %1, %0, [%3]\n" + " teq %1, #0\n" + " bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) + : "r" (&v->counter), "Ir" (i) + : "cc"); +@@ -132,6 +252,28 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) + return oldval; + } + ++static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *ptr, int old, int new) ++{ ++ unsigned long oldval, res; ++ ++ smp_mb(); ++ ++ do { ++ __asm__ __volatile__("@ atomic_cmpxchg_unchecked\n" ++ "ldrex %1, [%3]\n" ++ "mov %0, #0\n" ++ "teq %1, %4\n" ++ "strexeq %0, %5, [%3]\n" ++ : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) ++ : "r" (&ptr->counter), "Ir" (old), "r" (new) ++ : "cc"); ++ } while (res); ++ ++ smp_mb(); ++ ++ return oldval; ++} ++ + static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) + { + unsigned long tmp, tmp2; +@@ -207,6 +349,10 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) + #endif /* __LINUX_ARM_ARCH__ */ + + #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) ++{ ++ return xchg(&v->counter, new); ++} + + static inline int __atomic_add_unless(atomic_t *v, int a, int u) + { +@@ -219,11 +365,27 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) + } + + #define atomic_inc(v) atomic_add(1, v) ++static inline void atomic_inc_unchecked(atomic_unchecked_t *v) ++{ ++ atomic_add_unchecked(1, v); ++} + #define atomic_dec(v) atomic_sub(1, v) ++static inline void atomic_dec_unchecked(atomic_unchecked_t *v) ++{ ++ atomic_sub_unchecked(1, v); ++} + + #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) ++static inline int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) ++{ ++ return atomic_add_return_unchecked(1, v) == 0; ++} + #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) + #define atomic_inc_return(v) (atomic_add_return(1, v)) ++static inline int atomic_inc_return_unchecked(atomic_unchecked_t *v) ++{ ++ return atomic_add_return_unchecked(1, v); ++} + #define atomic_dec_return(v) (atomic_sub_return(1, v)) + #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) + +@@ -239,6 +401,14 @@ typedef struct { u64 __aligned(8) counter; } atomic64_t; @@ -674,23 +934,355 @@ index 86976d0..6610950 100644 #define ATOMIC64_INIT(i) { (i) } static inline u64 atomic64_read(atomic64_t *v) -@@ -459,6 +471,16 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u) +@@ -254,6 +424,19 @@ static inline u64 atomic64_read(atomic64_t *v) + return result; + } + ++static inline u64 atomic64_read_unchecked(atomic64_unchecked_t *v) ++{ ++ u64 result; ++ ++ __asm__ __volatile__("@ atomic64_read_unchecked\n" ++" ldrexd %0, %H0, [%1]" ++ : "=&r" (result) ++ : "r" (&v->counter), "Qo" (v->counter) ++ ); ++ ++ return result; ++} ++ + static inline void atomic64_set(atomic64_t *v, u64 i) + { + u64 tmp; +@@ -268,6 +451,20 @@ static inline void atomic64_set(atomic64_t *v, u64 i) + : "cc"); + } + ++static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, u64 i) ++{ ++ u64 tmp; ++ ++ __asm__ __volatile__("@ atomic64_set_unchecked\n" ++"1: ldrexd %0, %H0, [%2]\n" ++" strexd %0, %3, %H3, [%2]\n" ++" teq %0, #0\n" ++" bne 1b" ++ : "=&r" (tmp), "=Qo" (v->counter) ++ : "r" (&v->counter), "r" (i) ++ : "cc"); ++} ++ + static inline void atomic64_add(u64 i, atomic64_t *v) + { + u64 result; +@@ -276,6 +473,36 @@ static inline void atomic64_add(u64 i, atomic64_t *v) + __asm__ __volatile__("@ atomic64_add\n" + "1: ldrexd %0, %H0, [%3]\n" + " adds %0, %0, %4\n" ++" adcs %H0, %H0, %H4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strexd %1, %0, %H0, [%3]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "r" (i) ++ : "cc"); ++} ++ ++static inline void atomic64_add_unchecked(u64 i, atomic64_unchecked_t *v) ++{ ++ u64 result; ++ unsigned long tmp; ++ ++ __asm__ __volatile__("@ atomic64_add_unchecked\n" ++"1: ldrexd %0, %H0, [%3]\n" ++" adds %0, %0, %4\n" + " adc %H0, %H0, %H4\n" + " strexd %1, %0, %H0, [%3]\n" + " teq %1, #0\n" +@@ -287,12 +514,49 @@ static inline void atomic64_add(u64 i, atomic64_t *v) + + static inline u64 atomic64_add_return(u64 i, atomic64_t *v) + { +- u64 result; +- unsigned long tmp; ++ u64 result, tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_add_return\n" ++"1: ldrexd %1, %H1, [%3]\n" ++" adds %0, %1, %4\n" ++" adcs %H0, %H1, %H4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++" mov %H0, %H1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strexd %1, %0, %H0, [%3]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "r" (i) ++ : "cc"); ++ ++ smp_mb(); ++ ++ return result; ++} ++ ++static inline u64 atomic64_add_return_unchecked(u64 i, atomic64_unchecked_t *v) ++{ ++ u64 result; ++ unsigned long tmp; ++ ++ smp_mb(); ++ ++ __asm__ __volatile__("@ atomic64_add_return_unchecked\n" + "1: ldrexd %0, %H0, [%3]\n" + " adds %0, %0, %4\n" + " adc %H0, %H0, %H4\n" +@@ -316,6 +580,36 @@ static inline void atomic64_sub(u64 i, atomic64_t *v) + __asm__ __volatile__("@ atomic64_sub\n" + "1: ldrexd %0, %H0, [%3]\n" + " subs %0, %0, %4\n" ++" sbcs %H0, %H0, %H4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ ++" strexd %1, %0, %H0, [%3]\n" ++" teq %1, #0\n" ++" bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ ++ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "r" (i) ++ : "cc"); ++} ++ ++static inline void atomic64_sub_unchecked(u64 i, atomic64_unchecked_t *v) ++{ ++ u64 result; ++ unsigned long tmp; ++ ++ __asm__ __volatile__("@ atomic64_sub_unchecked\n" ++"1: ldrexd %0, %H0, [%3]\n" ++" subs %0, %0, %4\n" + " sbc %H0, %H0, %H4\n" + " strexd %1, %0, %H0, [%3]\n" + " teq %1, #0\n" +@@ -327,18 +621,32 @@ static inline void atomic64_sub(u64 i, atomic64_t *v) + + static inline u64 atomic64_sub_return(u64 i, atomic64_t *v) + { +- u64 result; +- unsigned long tmp; ++ u64 result, tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_sub_return\n" +-"1: ldrexd %0, %H0, [%3]\n" +-" subs %0, %0, %4\n" +-" sbc %H0, %H0, %H4\n" ++"1: ldrexd %1, %H1, [%3]\n" ++" subs %0, %1, %4\n" ++" sbc %H0, %H1, %H4\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++" mov %H0, %H1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ + " strexd %1, %0, %H0, [%3]\n" + " teq %1, #0\n" + " bne 1b" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++"\n4:\n" ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) + : "r" (&v->counter), "r" (i) + : "cc"); +@@ -372,6 +680,30 @@ static inline u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old, u64 new) + return oldval; + } + ++static inline u64 atomic64_cmpxchg_unchecked(atomic64_unchecked_t *ptr, u64 old, u64 new) ++{ ++ u64 oldval; ++ unsigned long res; ++ ++ smp_mb(); ++ ++ do { ++ __asm__ __volatile__("@ atomic64_cmpxchg_unchecked\n" ++ "ldrexd %1, %H1, [%3]\n" ++ "mov %0, #0\n" ++ "teq %1, %4\n" ++ "teqeq %H1, %H4\n" ++ "strexdeq %0, %5, %H5, [%3]" ++ : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) ++ : "r" (&ptr->counter), "r" (old), "r" (new) ++ : "cc"); ++ } while (res); ++ ++ smp_mb(); ++ ++ return oldval; ++} ++ + static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new) + { + u64 result; +@@ -395,21 +727,34 @@ static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new) + + static inline u64 atomic64_dec_if_positive(atomic64_t *v) + { +- u64 result; +- unsigned long tmp; ++ u64 result, tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_dec_if_positive\n" +-"1: ldrexd %0, %H0, [%3]\n" +-" subs %0, %0, #1\n" +-" sbc %H0, %H0, #0\n" ++"1: ldrexd %1, %H1, [%3]\n" ++" subs %0, %1, #1\n" ++" sbc %H0, %H1, #0\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++" mov %0, %1\n" ++" mov %H0, %H1\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ + " teq %H0, #0\n" +-" bmi 2f\n" ++" bmi 4f\n" + " strexd %1, %0, %H0, [%3]\n" + " teq %1, #0\n" + " bne 1b\n" +-"2:" ++"4:\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) + : "r" (&v->counter) + : "cc"); +@@ -432,13 +777,25 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u) + " teq %0, %5\n" + " teqeq %H0, %H5\n" + " moveq %1, #0\n" +-" beq 2f\n" ++" beq 4f\n" + " adds %0, %0, %6\n" + " adc %H0, %H0, %H6\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++" bvc 3f\n" ++"2: bkpt 0xf103\n" ++"3:\n" ++#endif ++ + " strexd %2, %0, %H0, [%4]\n" + " teq %2, #0\n" + " bne 1b\n" +-"2:" ++"4:\n" ++ ++#ifdef CONFIG_PAX_REFCOUNT ++ _ASM_EXTABLE(2b, 4b) ++#endif ++ + : "=&r" (val), "+r" (ret), "=&r" (tmp), "+Qo" (v->counter) + : "r" (&v->counter), "r" (u), "r" (a) + : "cc"); +@@ -451,10 +808,13 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u) + + #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) + #define atomic64_inc(v) atomic64_add(1LL, (v)) ++#define atomic64_inc_unchecked(v) atomic64_add_unchecked(1LL, (v)) + #define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) ++#define atomic64_inc_return_unchecked(v) atomic64_add_return_unchecked(1LL, (v)) + #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) + #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) + #define atomic64_dec(v) atomic64_sub(1LL, (v)) ++#define atomic64_dec_unchecked(v) atomic64_sub_unchecked(1LL, (v)) + #define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) +diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h +index 75fe66b..2255c86 100644 +--- a/arch/arm/include/asm/cache.h ++++ b/arch/arm/include/asm/cache.h +@@ -4,8 +4,10 @@ + #ifndef __ASMARM_CACHE_H + #define __ASMARM_CACHE_H -+#define atomic64_read_unchecked(v) atomic64_read(v) -+#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) -+#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) -+#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) -+#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) -+#define atomic64_inc_unchecked(v) atomic64_inc(v) -+#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) -+#define atomic64_dec_unchecked(v) atomic64_dec(v) -+#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) ++#include <linux/const.h> + - #endif /* !CONFIG_GENERIC_ATOMIC64 */ - #endif - #endif + #define L1_CACHE_SHIFT CONFIG_ARM_L1_CACHE_SHIFT +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + /* + * Memory returned by kmalloc() may be used for DMA, so we must make +diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h +index d5d8d5c..ad92c96 100644 +--- a/arch/arm/include/asm/cacheflush.h ++++ b/arch/arm/include/asm/cacheflush.h +@@ -108,7 +108,7 @@ struct cpu_cache_fns { + void (*dma_unmap_area)(const void *, size_t, int); + + void (*dma_flush_range)(const void *, const void *); +-}; ++} __no_const; + + /* + * Select the calling method diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 0e9ce8d..6ef1e03 100644 --- a/arch/arm/include/asm/elf.h @@ -734,6 +1326,68 @@ index e51b1e8..32a3113 100644 KM_TYPE_NR }; +diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h +index 53426c6..c7baff3 100644 +--- a/arch/arm/include/asm/outercache.h ++++ b/arch/arm/include/asm/outercache.h +@@ -35,7 +35,7 @@ struct outer_cache_fns { + #endif + void (*set_debug)(unsigned long); + void (*resume)(void); +-}; ++} __no_const; + + #ifdef CONFIG_OUTER_CACHE + +diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h +index ca94653..6ac0d56 100644 +--- a/arch/arm/include/asm/page.h ++++ b/arch/arm/include/asm/page.h +@@ -123,7 +123,7 @@ struct cpu_user_fns { + void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr); + void (*cpu_copy_user_highpage)(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma); +-}; ++} __no_const; + + #ifdef MULTI_USER + extern struct cpu_user_fns cpu_user; +diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h +index 984014b..a6d914f 100644 +--- a/arch/arm/include/asm/system.h ++++ b/arch/arm/include/asm/system.h +@@ -90,6 +90,8 @@ void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, + + #define xchg(ptr,x) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) ++#define xchg_unchecked(ptr,x) \ ++ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + + extern asmlinkage void c_backtrace(unsigned long fp, int pmode); + +@@ -101,7 +103,7 @@ extern int __pure cpu_architecture(void); + extern void cpu_init(void); + + void arm_machine_restart(char mode, const char *cmd); +-extern void (*arm_pm_restart)(char str, const char *cmd); ++extern void (*arm_pm_restart)(char str, const char *cmd) __noreturn; + + #define UDBG_UNDEFINED (1 << 0) + #define UDBG_SYSCALL (1 << 1) +@@ -526,6 +528,13 @@ static inline unsigned long long __cmpxchg64_mb(volatile void *ptr, + + #endif /* __LINUX_ARM_ARCH__ >= 6 */ + ++#define _ASM_EXTABLE(from, to) \ ++" .pushsection __ex_table,\"a\"\n"\ ++" .align 3\n" \ ++" .long " #from ", " #to"\n" \ ++" .popsection" ++ ++ + #endif /* __ASSEMBLY__ */ + + #define arch_align_stack(x) (x) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index b293616..96310e5 100644 --- a/arch/arm/include/asm/uaccess.h @@ -809,7 +1463,7 @@ index 5b0bce6..becd81c 100644 EXPORT_SYMBOL(__get_user_1); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c -index 3d0c6fb..3dcae52 100644 +index 3d0c6fb..9d326fa 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -28,7 +28,6 @@ @@ -820,7 +1474,33 @@ index 3d0c6fb..3dcae52 100644 #include <linux/hw_breakpoint.h> #include <linux/cpuidle.h> -@@ -484,12 +483,6 @@ unsigned long get_wchan(struct task_struct *p) +@@ -92,7 +91,7 @@ static int __init hlt_setup(char *__unused) + __setup("nohlt", nohlt_setup); + __setup("hlt", hlt_setup); + +-void arm_machine_restart(char mode, const char *cmd) ++__noreturn void arm_machine_restart(char mode, const char *cmd) + { + /* Disable interrupts first */ + local_irq_disable(); +@@ -134,7 +133,7 @@ void arm_machine_restart(char mode, const char *cmd) + void (*pm_power_off)(void); + EXPORT_SYMBOL(pm_power_off); + +-void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart; ++void (*arm_pm_restart)(char str, const char *cmd) __noreturn = arm_machine_restart; + EXPORT_SYMBOL_GPL(arm_pm_restart); + + static void do_nothing(void *unused) +@@ -248,6 +247,7 @@ void machine_power_off(void) + machine_shutdown(); + if (pm_power_off) + pm_power_off(); ++ BUG(); + } + + void machine_restart(char *cmd) +@@ -484,12 +484,6 @@ unsigned long get_wchan(struct task_struct *p) return 0; } @@ -833,6 +1513,27 @@ index 3d0c6fb..3dcae52 100644 #ifdef CONFIG_MMU /* * The vectors page is always readable from user space for the +diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c +index 8fc2c8f..064c150 100644 +--- a/arch/arm/kernel/setup.c ++++ b/arch/arm/kernel/setup.c +@@ -108,13 +108,13 @@ struct processor processor __read_mostly; + struct cpu_tlb_fns cpu_tlb __read_mostly; + #endif + #ifdef MULTI_USER +-struct cpu_user_fns cpu_user __read_mostly; ++struct cpu_user_fns cpu_user __read_only; + #endif + #ifdef MULTI_CACHE +-struct cpu_cache_fns cpu_cache __read_mostly; ++struct cpu_cache_fns cpu_cache __read_only; + #endif + #ifdef CONFIG_OUTER_CACHE +-struct outer_cache_fns outer_cache __read_mostly; ++struct outer_cache_fns outer_cache __read_only; + EXPORT_SYMBOL(outer_cache); + #endif + diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 99a5727..a3d5bb1 100644 --- a/arch/arm/kernel/traps.c @@ -883,6 +1584,18 @@ index 66a477a..bee61d3 100644 .pushsection .fixup,"ax" .align 0 +diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S +index 6ee2f67..d1cce76 100644 +--- a/arch/arm/lib/copy_page.S ++++ b/arch/arm/lib/copy_page.S +@@ -10,6 +10,7 @@ + * ASM optimised string functions + */ + #include <linux/linkage.h> ++#include <linux/const.h> + #include <asm/assembler.h> + #include <asm/asm-offsets.h> + #include <asm/cache.h> diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index d066df6..df28194 100644 --- a/arch/arm/lib/copy_to_user.S @@ -980,6 +1693,19 @@ index 025f742..8432b08 100644 { /* * This test is stubbed out of the main function above to keep +diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c +index e9d5f4a..f099699 100644 +--- a/arch/arm/mach-omap2/board-n8x0.c ++++ b/arch/arm/mach-omap2/board-n8x0.c +@@ -593,7 +593,7 @@ static int n8x0_menelaus_late_init(struct device *dev) + } + #endif + +-static struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = { ++static struct menelaus_platform_data n8x0_menelaus_platform_data __initconst = { + .late_init = n8x0_menelaus_late_init, + }; + diff --git a/arch/arm/mach-ux500/mbox-db5500.c b/arch/arm/mach-ux500/mbox-db5500.c index 2b2d51c..0127490 100644 --- a/arch/arm/mach-ux500/mbox-db5500.c @@ -994,7 +1720,7 @@ index 2b2d51c..0127490 100644 static int mbox_show(struct seq_file *s, void *data) { diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c -index aa33949..b242a2f 100644 +index aa33949..d366075 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -183,6 +183,13 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, @@ -1045,6 +1771,27 @@ index aa33949..b242a2f 100644 /* * First Level Translation Fault Handler * +@@ -628,6 +662,20 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) + const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); + struct siginfo info; + ++#ifdef CONFIG_PAX_REFCOUNT ++ if (fsr_fs(ifsr) == 2) { ++ unsigned int bkpt; ++ ++ if (!probe_kernel_address((unsigned int *)addr, bkpt) && bkpt == 0xe12f1073) { ++ current->thread.error_code = ifsr; ++ current->thread.trap_no = 0; ++ pax_report_refcount_overflow(regs); ++ fixup_exception(regs); ++ return; ++ } ++ } ++#endif ++ + if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) + return; + diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 44b628e..623ee2a 100644 --- a/arch/arm/mm/mmap.c @@ -1098,6 +1845,48 @@ index 44b628e..623ee2a 100644 /* * Remember the place where we stopped the search: */ +diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h +index 4c1a363..df311d0 100644 +--- a/arch/arm/plat-samsung/include/plat/dma-ops.h ++++ b/arch/arm/plat-samsung/include/plat/dma-ops.h +@@ -41,7 +41,7 @@ struct samsung_dma_ops { + int (*started)(unsigned ch); + int (*flush)(unsigned ch); + int (*stop)(unsigned ch); +-}; ++} __no_const; + + extern void *samsung_dmadev_get_ops(void); + extern void *s3c_dma_get_ops(void); +diff --git a/arch/arm/plat-samsung/include/plat/ehci.h b/arch/arm/plat-samsung/include/plat/ehci.h +index 5f28cae..3d23723 100644 +--- a/arch/arm/plat-samsung/include/plat/ehci.h ++++ b/arch/arm/plat-samsung/include/plat/ehci.h +@@ -14,7 +14,7 @@ + struct s5p_ehci_platdata { + int (*phy_init)(struct platform_device *pdev, int type); + int (*phy_exit)(struct platform_device *pdev, int type); +-}; ++} __no_const; + + extern void s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd); + +diff --git a/arch/avr32/include/asm/cache.h b/arch/avr32/include/asm/cache.h +index c3a58a1..78fbf54 100644 +--- a/arch/avr32/include/asm/cache.h ++++ b/arch/avr32/include/asm/cache.h +@@ -1,8 +1,10 @@ + #ifndef __ASM_AVR32_CACHE_H + #define __ASM_AVR32_CACHE_H + ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT 5 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + /* + * Memory returned by kmalloc() may be used for DMA, so we must make diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h index 3b3159b..425ea94 100644 --- a/arch/avr32/include/asm/elf.h @@ -1177,6 +1966,60 @@ index f7040a1..db9f300 100644 if (exception_trace && printk_ratelimit()) printk("%s%s[%d]: segfault at %08lx pc %08lx " "sp %08lx ecr %lu\n", +diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h +index 568885a..f8008df 100644 +--- a/arch/blackfin/include/asm/cache.h ++++ b/arch/blackfin/include/asm/cache.h +@@ -7,6 +7,7 @@ + #ifndef __ARCH_BLACKFIN_CACHE_H + #define __ARCH_BLACKFIN_CACHE_H + ++#include <linux/const.h> + #include <linux/linkage.h> /* for asmlinkage */ + + /* +@@ -14,7 +15,7 @@ + * Blackfin loads 32 bytes for cache + */ + #define L1_CACHE_SHIFT 5 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + #define SMP_CACHE_BYTES L1_CACHE_BYTES + + #define ARCH_DMA_MINALIGN L1_CACHE_BYTES +diff --git a/arch/cris/include/arch-v10/arch/cache.h b/arch/cris/include/arch-v10/arch/cache.h +index aea2718..3639a60 100644 +--- a/arch/cris/include/arch-v10/arch/cache.h ++++ b/arch/cris/include/arch-v10/arch/cache.h +@@ -1,8 +1,9 @@ + #ifndef _ASM_ARCH_CACHE_H + #define _ASM_ARCH_CACHE_H + ++#include <linux/const.h> + /* Etrax 100LX have 32-byte cache-lines. */ +-#define L1_CACHE_BYTES 32 + #define L1_CACHE_SHIFT 5 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* _ASM_ARCH_CACHE_H */ +diff --git a/arch/cris/include/arch-v32/arch/cache.h b/arch/cris/include/arch-v32/arch/cache.h +index 1de779f..336fad3 100644 +--- a/arch/cris/include/arch-v32/arch/cache.h ++++ b/arch/cris/include/arch-v32/arch/cache.h +@@ -1,11 +1,12 @@ + #ifndef _ASM_CRIS_ARCH_CACHE_H + #define _ASM_CRIS_ARCH_CACHE_H + ++#include <linux/const.h> + #include <arch/hwregs/dma.h> + + /* A cache-line is 32 bytes. */ +-#define L1_CACHE_BYTES 32 + #define L1_CACHE_SHIFT 5 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define __read_mostly __attribute__((__section__(".data.read_mostly"))) + diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 0d8a7d6..d0c9ff5 100644 --- a/arch/frv/include/asm/atomic.h @@ -1198,6 +2041,23 @@ index 0d8a7d6..d0c9ff5 100644 static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) { int c, old; +diff --git a/arch/frv/include/asm/cache.h b/arch/frv/include/asm/cache.h +index 2797163..c2a401d 100644 +--- a/arch/frv/include/asm/cache.h ++++ b/arch/frv/include/asm/cache.h +@@ -12,10 +12,11 @@ + #ifndef __ASM_CACHE_H + #define __ASM_CACHE_H + ++#include <linux/const.h> + + /* bytes per L1 cache line */ + #define L1_CACHE_SHIFT (CONFIG_FRV_L1_CACHE_SHIFT) +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define __cacheline_aligned __attribute__((aligned(L1_CACHE_BYTES))) + #define ____cacheline_aligned __attribute__((aligned(L1_CACHE_BYTES))) diff --git a/arch/frv/include/asm/kmap_types.h b/arch/frv/include/asm/kmap_types.h index f8e16b2..c73ff79 100644 --- a/arch/frv/include/asm/kmap_types.h @@ -1242,6 +2102,40 @@ index 385fd30..6c3d97e 100644 goto success; addr = vma->vm_end; } +diff --git a/arch/h8300/include/asm/cache.h b/arch/h8300/include/asm/cache.h +index c635028..6d9445a 100644 +--- a/arch/h8300/include/asm/cache.h ++++ b/arch/h8300/include/asm/cache.h +@@ -1,8 +1,10 @@ + #ifndef __ARCH_H8300_CACHE_H + #define __ARCH_H8300_CACHE_H + ++#include <linux/const.h> ++ + /* bytes per L1 cache line */ +-#define L1_CACHE_BYTES 4 ++#define L1_CACHE_BYTES _AC(4,UL) + + /* m68k-elf-gcc 2.95.2 doesn't like these */ + +diff --git a/arch/hexagon/include/asm/cache.h b/arch/hexagon/include/asm/cache.h +index 0f01de2..d37d309 100644 +--- a/arch/hexagon/include/asm/cache.h ++++ b/arch/hexagon/include/asm/cache.h +@@ -21,9 +21,11 @@ + #ifndef __ASM_CACHE_H + #define __ASM_CACHE_H + ++#include <linux/const.h> ++ + /* Bytes per L1 cache line */ +-#define L1_CACHE_SHIFT (5) +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_SHIFT 5 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define __cacheline_aligned __aligned(L1_CACHE_BYTES) + #define ____cacheline_aligned __aligned(L1_CACHE_BYTES) diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 3fad89e..3047da5 100644 --- a/arch/ia64/include/asm/atomic.h @@ -1263,6 +2157,27 @@ index 3fad89e..3047da5 100644 /* Atomic operations are already serializing */ #define smp_mb__before_atomic_dec() barrier() #define smp_mb__after_atomic_dec() barrier() +diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h +index 988254a..e1ee885 100644 +--- a/arch/ia64/include/asm/cache.h ++++ b/arch/ia64/include/asm/cache.h +@@ -1,6 +1,7 @@ + #ifndef _ASM_IA64_CACHE_H + #define _ASM_IA64_CACHE_H + ++#include <linux/const.h> + + /* + * Copyright (C) 1998-2000 Hewlett-Packard Co +@@ -9,7 +10,7 @@ + + /* Bytes per L1 (data) cache line. */ + #define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #ifdef CONFIG_SMP + # define SMP_CACHE_SHIFT L1_CACHE_SHIFT diff --git a/arch/ia64/include/asm/elf.h b/arch/ia64/include/asm/elf.h index b5298eb..67c6e62 100644 --- a/arch/ia64/include/asm/elf.h @@ -1578,6 +2493,22 @@ index 00cb0e2..2ad8024 100644 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); down_write(¤t->mm->mmap_sem); if (insert_vm_struct(current->mm, vma)) { +diff --git a/arch/m32r/include/asm/cache.h b/arch/m32r/include/asm/cache.h +index 40b3ee9..8c2c112 100644 +--- a/arch/m32r/include/asm/cache.h ++++ b/arch/m32r/include/asm/cache.h +@@ -1,8 +1,10 @@ + #ifndef _ASM_M32R_CACHE_H + #define _ASM_M32R_CACHE_H + ++#include <linux/const.h> ++ + /* L1 cache line size */ + #define L1_CACHE_SHIFT 4 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* _ASM_M32R_CACHE_H */ diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c index 82abd15..d95ae5d 100644 --- a/arch/m32r/lib/usercopy.c @@ -1602,6 +2533,41 @@ index 82abd15..d95ae5d 100644 prefetchw(to); if (access_ok(VERIFY_READ, from, n)) __copy_user_zeroing(to,from,n); +diff --git a/arch/m68k/include/asm/cache.h b/arch/m68k/include/asm/cache.h +index 0395c51..5f26031 100644 +--- a/arch/m68k/include/asm/cache.h ++++ b/arch/m68k/include/asm/cache.h +@@ -4,9 +4,11 @@ + #ifndef __ARCH_M68K_CACHE_H + #define __ARCH_M68K_CACHE_H + ++#include <linux/const.h> ++ + /* bytes per L1 cache line */ + #define L1_CACHE_SHIFT 4 +-#define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define ARCH_DMA_MINALIGN L1_CACHE_BYTES + +diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h +index 4efe96a..60e8699 100644 +--- a/arch/microblaze/include/asm/cache.h ++++ b/arch/microblaze/include/asm/cache.h +@@ -13,11 +13,12 @@ + #ifndef _ASM_MICROBLAZE_CACHE_H + #define _ASM_MICROBLAZE_CACHE_H + ++#include <linux/const.h> + #include <asm/registers.h> + + #define L1_CACHE_SHIFT 5 + /* word-granular cache in microblaze */ +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define SMP_CACHE_BYTES L1_CACHE_BYTES + diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 1d93f81..67794d0 100644 --- a/arch/mips/include/asm/atomic.h @@ -1634,6 +2600,23 @@ index 1d93f81..67794d0 100644 #endif /* CONFIG_64BIT */ /* +diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h +index b4db69f..8f3b093 100644 +--- a/arch/mips/include/asm/cache.h ++++ b/arch/mips/include/asm/cache.h +@@ -9,10 +9,11 @@ + #ifndef _ASM_CACHE_H + #define _ASM_CACHE_H + ++#include <linux/const.h> + #include <kmalloc.h> + + #define L1_CACHE_SHIFT CONFIG_MIPS_L1_CACHE_SHIFT +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define SMP_CACHE_SHIFT L1_CACHE_SHIFT + #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 455c0ac..ad65fbe 100644 --- a/arch/mips/include/asm/elf.h @@ -1852,6 +2835,66 @@ index 302d779..7d35bf8 100644 - - return ret; -} +diff --git a/arch/mn10300/proc-mn103e010/include/proc/cache.h b/arch/mn10300/proc-mn103e010/include/proc/cache.h +index 967d144..db12197 100644 +--- a/arch/mn10300/proc-mn103e010/include/proc/cache.h ++++ b/arch/mn10300/proc-mn103e010/include/proc/cache.h +@@ -11,12 +11,14 @@ + #ifndef _ASM_PROC_CACHE_H + #define _ASM_PROC_CACHE_H + ++#include <linux/const.h> ++ + /* L1 cache */ + + #define L1_CACHE_NWAYS 4 /* number of ways in caches */ + #define L1_CACHE_NENTRIES 256 /* number of entries in each way */ +-#define L1_CACHE_BYTES 16 /* bytes per entry */ + #define L1_CACHE_SHIFT 4 /* shift for bytes per entry */ ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per entry */ + #define L1_CACHE_WAYDISP 0x1000 /* displacement of one way from the next */ + + #define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */ +diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h +index bcb5df2..84fabd2 100644 +--- a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h ++++ b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h +@@ -16,13 +16,15 @@ + #ifndef _ASM_PROC_CACHE_H + #define _ASM_PROC_CACHE_H + ++#include <linux/const.h> ++ + /* + * L1 cache + */ + #define L1_CACHE_NWAYS 4 /* number of ways in caches */ + #define L1_CACHE_NENTRIES 128 /* number of entries in each way */ +-#define L1_CACHE_BYTES 32 /* bytes per entry */ + #define L1_CACHE_SHIFT 5 /* shift for bytes per entry */ ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per entry */ + #define L1_CACHE_WAYDISP 0x1000 /* distance from one way to the next */ + + #define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */ +diff --git a/arch/openrisc/include/asm/cache.h b/arch/openrisc/include/asm/cache.h +index 4ce7a01..449202a 100644 +--- a/arch/openrisc/include/asm/cache.h ++++ b/arch/openrisc/include/asm/cache.h +@@ -19,11 +19,13 @@ + #ifndef __ASM_OPENRISC_CACHE_H + #define __ASM_OPENRISC_CACHE_H + ++#include <linux/const.h> ++ + /* FIXME: How can we replace these with values from the CPU... + * they shouldn't be hard-coded! + */ + +-#define L1_CACHE_BYTES 16 + #define L1_CACHE_SHIFT 4 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* __ASM_OPENRISC_CACHE_H */ diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 4054b31..a10c105 100644 --- a/arch/parisc/include/asm/atomic.h @@ -1873,6 +2916,34 @@ index 4054b31..a10c105 100644 #endif /* !CONFIG_64BIT */ +diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h +index 47f11c7..3420df2 100644 +--- a/arch/parisc/include/asm/cache.h ++++ b/arch/parisc/include/asm/cache.h +@@ -5,6 +5,7 @@ + #ifndef __ARCH_PARISC_CACHE_H + #define __ARCH_PARISC_CACHE_H + ++#include <linux/const.h> + + /* + * PA 2.0 processors have 64-byte cachelines; PA 1.1 processors have +@@ -15,13 +16,13 @@ + * just ruin performance. + */ + #ifdef CONFIG_PA20 +-#define L1_CACHE_BYTES 64 + #define L1_CACHE_SHIFT 6 + #else +-#define L1_CACHE_BYTES 32 + #define L1_CACHE_SHIFT 5 + #endif + ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) ++ + #ifndef __ASSEMBLY__ + + #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 19f6cb1..6c78cf2 100644 --- a/arch/parisc/include/asm/elf.h @@ -2256,6 +3327,27 @@ index 02e41b5..ec6e26c 100644 #endif /* __powerpc64__ */ #endif /* __KERNEL__ */ +diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h +index 4b50941..5605819 100644 +--- a/arch/powerpc/include/asm/cache.h ++++ b/arch/powerpc/include/asm/cache.h +@@ -3,6 +3,7 @@ + + #ifdef __KERNEL__ + ++#include <linux/const.h> + + /* bytes per L1 cache line */ + #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) +@@ -22,7 +23,7 @@ + #define L1_CACHE_SHIFT 7 + #endif + +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define SMP_CACHE_BYTES L1_CACHE_BYTES + diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index 3bf9cca..e7457d0 100644 --- a/arch/powerpc/include/asm/elf.h @@ -2636,6 +3728,34 @@ index cf9c69b..ebc9640 100644 mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD lwz r4,_DAR(r1) +diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c +index 745c1e7..59d97a6 100644 +--- a/arch/powerpc/kernel/irq.c ++++ b/arch/powerpc/kernel/irq.c +@@ -547,9 +547,6 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, + host->ops = ops; + host->of_node = of_node_get(of_node); + +- if (host->ops->match == NULL) +- host->ops->match = default_irq_host_match; +- + raw_spin_lock_irqsave(&irq_big_lock, flags); + + /* If it's a legacy controller, check for duplicates and +@@ -622,7 +619,12 @@ struct irq_host *irq_find_host(struct device_node *node) + */ + raw_spin_lock_irqsave(&irq_big_lock, flags); + list_for_each_entry(h, &irq_hosts, link) +- if (h->ops->match(h, node)) { ++ if (h->ops->match) { ++ if (h->ops->match(h, node)) { ++ found = h; ++ break; ++ } ++ } else if (default_irq_host_match(h, node)) { + found = h; + break; + } diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 0b6d796..d760ddb 100644 --- a/arch/powerpc/kernel/module_32.c @@ -3104,6 +4224,22 @@ index 8517d2a..d2738d4 100644 #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() #define smp_mb__before_atomic_inc() smp_mb() +diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h +index 2a30d5a..5e5586f 100644 +--- a/arch/s390/include/asm/cache.h ++++ b/arch/s390/include/asm/cache.h +@@ -11,8 +11,10 @@ + #ifndef __ARCH_S390_CACHE_H + #define __ARCH_S390_CACHE_H + +-#define L1_CACHE_BYTES 256 ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT 8 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + #define NET_SKB_PAD 32 + + #define __read_mostly __attribute__((__section__(".data..read_mostly"))) diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 547f1a6..0b22b53 100644 --- a/arch/s390/include/asm/elf.h @@ -3258,10 +4394,10 @@ index dfcb343..eda788a 100644 if (r_type == R_390_GOTPC) *(unsigned int *) loc = val; diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c -index 9451b21..ed8956f 100644 +index 53088e2..9f44a36 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c -@@ -321,39 +321,3 @@ unsigned long get_wchan(struct task_struct *p) +@@ -320,39 +320,3 @@ unsigned long get_wchan(struct task_struct *p) } return 0; } @@ -3302,7 +4438,7 @@ index 9451b21..ed8956f 100644 - return ret; -} diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c -index f09c748..cf9ec1d 100644 +index a0155c0..34cc491 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -92,10 +92,22 @@ void arch_pick_mmap_layout(struct mm_struct *mm) @@ -3351,6 +4487,21 @@ index f09c748..cf9ec1d 100644 mm->get_unmapped_area = s390_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } +diff --git a/arch/score/include/asm/cache.h b/arch/score/include/asm/cache.h +index ae3d59f..f65f075 100644 +--- a/arch/score/include/asm/cache.h ++++ b/arch/score/include/asm/cache.h +@@ -1,7 +1,9 @@ + #ifndef _ASM_SCORE_CACHE_H + #define _ASM_SCORE_CACHE_H + ++#include <linux/const.h> ++ + #define L1_CACHE_SHIFT 4 +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif /* _ASM_SCORE_CACHE_H */ diff --git a/arch/score/include/asm/system.h b/arch/score/include/asm/system.h index 589d5c7..669e274 100644 --- a/arch/score/include/asm/system.h @@ -3377,6 +4528,23 @@ index 25d0803..d6c8e36 100644 -{ - return sp; -} +diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h +index ef9e555..331bd29 100644 +--- a/arch/sh/include/asm/cache.h ++++ b/arch/sh/include/asm/cache.h +@@ -9,10 +9,11 @@ + #define __ASM_SH_CACHE_H + #ifdef __KERNEL__ + ++#include <linux/const.h> + #include <linux/init.h> + #include <cpu/cache.h> + +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #define __read_mostly __attribute__((__section__(".data..read_mostly"))) + diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index afeb710..d1d1289 100644 --- a/arch/sh/mm/mmap.c @@ -3480,17 +4648,19 @@ index ad1fb5d..fc5315b 100644 VMLINUX_MAIN += $(patsubst %/, %/lib.a, $(libs-y)) $(libs-y) VMLINUX_MAIN += $(drivers-y) $(net-y) -diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h -index 8ff83d8..4a459c2 100644 ---- a/arch/sparc/include/asm/atomic.h -+++ b/arch/sparc/include/asm/atomic.h -@@ -4,5 +4,6 @@ - #include <asm/atomic_64.h> - #else - #include <asm/atomic_32.h> +diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h +index 5c3c8b6..ba822fa 100644 +--- a/arch/sparc/include/asm/atomic_32.h ++++ b/arch/sparc/include/asm/atomic_32.h +@@ -13,6 +13,8 @@ + + #include <linux/types.h> + +#include <asm-generic/atomic64.h> - #endif - #endif ++ + #ifdef __KERNEL__ + + #include <asm/system.h> diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 9f421df..b81fc12 100644 --- a/arch/sparc/include/asm/atomic_64.h @@ -3682,15 +4852,20 @@ index 9f421df..b81fc12 100644 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h -index 69358b5..17b4745 100644 +index 69358b5..9d0d492 100644 --- a/arch/sparc/include/asm/cache.h +++ b/arch/sparc/include/asm/cache.h -@@ -10,7 +10,7 @@ +@@ -7,10 +7,12 @@ + #ifndef _SPARC_CACHE_H + #define _SPARC_CACHE_H + ++#include <linux/const.h> ++ #define ARCH_SLAB_MINALIGN __alignof__(unsigned long long) #define L1_CACHE_SHIFT 5 -#define L1_CACHE_BYTES 32 -+#define L1_CACHE_BYTES 32UL ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #ifdef CONFIG_SPARC32 #define SMP_CACHE_BYTES_SHIFT 5 @@ -5739,6 +6914,24 @@ index 27fe667..36d474c 100644 /* Atomic dec and inc don't implement barrier, so provide them if needed. */ #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() +diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h +index 392e533..536b092 100644 +--- a/arch/tile/include/asm/cache.h ++++ b/arch/tile/include/asm/cache.h +@@ -15,11 +15,12 @@ + #ifndef _ASM_TILE_CACHE_H + #define _ASM_TILE_CACHE_H + ++#include <linux/const.h> + #include <arch/chip.h> + + /* bytes per L1 data cache line */ + #define L1_CACHE_SHIFT CHIP_L1D_LOG_LINE_SIZE() +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + /* bytes per L2 cache line */ + #define L2_CACHE_SHIFT CHIP_L2_LOG_LINE_SIZE() diff --git a/arch/um/Makefile b/arch/um/Makefile index 7730af6..cce5b19 100644 --- a/arch/um/Makefile @@ -5754,6 +6947,26 @@ index 7730af6..cce5b19 100644 #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) +diff --git a/arch/um/include/asm/cache.h b/arch/um/include/asm/cache.h +index 19e1bdd..3665b77 100644 +--- a/arch/um/include/asm/cache.h ++++ b/arch/um/include/asm/cache.h +@@ -1,6 +1,7 @@ + #ifndef __UM_CACHE_H + #define __UM_CACHE_H + ++#include <linux/const.h> + + #if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) + # define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) +@@ -12,6 +13,6 @@ + # define L1_CACHE_SHIFT 5 + #endif + +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + #endif diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h index 6c03acd..a5e0215 100644 --- a/arch/um/include/asm/kmap_types.h @@ -5807,6 +7020,23 @@ index c533835..84db18e 100644 unsigned long get_wchan(struct task_struct *p) { unsigned long stack_page, sp, ip; +diff --git a/arch/unicore32/include/asm/cache.h b/arch/unicore32/include/asm/cache.h +index ad8f795..2c7eec6 100644 +--- a/arch/unicore32/include/asm/cache.h ++++ b/arch/unicore32/include/asm/cache.h +@@ -12,8 +12,10 @@ + #ifndef __UNICORE_CACHE_H__ + #define __UNICORE_CACHE_H__ + +-#define L1_CACHE_SHIFT (5) +-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) ++#include <linux/const.h> ++ ++#define L1_CACHE_SHIFT 5 ++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + + /* + * Memory returned by kmalloc() may be used for DMA, so we must make diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index efb4294..61bc18c 100644 --- a/arch/x86/Kconfig @@ -18517,10 +19747,10 @@ index 9299410..ade2f9b 100644 spin_unlock(&vcpu->kvm->mmu_lock); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c -index e32243e..a6e6172 100644 +index 94a4672..5c6b853 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c -@@ -3400,7 +3400,11 @@ static void reload_tss(struct kvm_vcpu *vcpu) +@@ -3405,7 +3405,11 @@ static void reload_tss(struct kvm_vcpu *vcpu) int cpu = raw_smp_processor_id(); struct svm_cpu_data *sd = per_cpu(svm_data, cpu); @@ -18532,7 +19762,7 @@ index e32243e..a6e6172 100644 load_TR_desc(); } -@@ -3778,6 +3782,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) +@@ -3783,6 +3787,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #endif #endif @@ -25137,6 +26367,67 @@ index b095739..8c17bcd 100644 struct trap_info; void xen_copy_trap_info(struct trap_info *traps); +diff --git a/arch/xtensa/variants/dc232b/include/variant/core.h b/arch/xtensa/variants/dc232b/include/variant/core.h +index 525bd3d..ef888b1 100644 +--- a/arch/xtensa/variants/dc232b/include/variant/core.h ++++ b/arch/xtensa/variants/dc232b/include/variant/core.h +@@ -119,9 +119,9 @@ + ----------------------------------------------------------------------*/ + + #define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */ +-#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */ + #define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */ + #define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */ ++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ + + #define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */ + #define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */ +diff --git a/arch/xtensa/variants/fsf/include/variant/core.h b/arch/xtensa/variants/fsf/include/variant/core.h +index 2f33760..835e50a 100644 +--- a/arch/xtensa/variants/fsf/include/variant/core.h ++++ b/arch/xtensa/variants/fsf/include/variant/core.h +@@ -11,6 +11,7 @@ + #ifndef _XTENSA_CORE_H + #define _XTENSA_CORE_H + ++#include <linux/const.h> + + /**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED +@@ -112,9 +113,9 @@ + ----------------------------------------------------------------------*/ + + #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ +-#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ + #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ + #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ ++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ + + #define XCHAL_ICACHE_SIZE 8192 /* I-cache size in bytes or 0 */ + #define XCHAL_DCACHE_SIZE 8192 /* D-cache size in bytes or 0 */ +diff --git a/arch/xtensa/variants/s6000/include/variant/core.h b/arch/xtensa/variants/s6000/include/variant/core.h +index af00795..2bb8105 100644 +--- a/arch/xtensa/variants/s6000/include/variant/core.h ++++ b/arch/xtensa/variants/s6000/include/variant/core.h +@@ -11,6 +11,7 @@ + #ifndef _XTENSA_CORE_CONFIGURATION_H + #define _XTENSA_CORE_CONFIGURATION_H + ++#include <linux/const.h> + + /**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED +@@ -118,9 +119,9 @@ + ----------------------------------------------------------------------*/ + + #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ +-#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ + #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ + #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ ++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ + + #define XCHAL_ICACHE_SIZE 32768 /* I-cache size in bytes or 0 */ + #define XCHAL_DCACHE_SIZE 32768 /* D-cache size in bytes or 0 */ diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c index 58916af..9cb880b 100644 --- a/block/blk-iopoll.c @@ -25177,7 +26468,7 @@ index 1366a89..e17f54b 100644 struct list_head *cpu_list, local_list; diff --git a/block/bsg.c b/block/bsg.c -index 702f131..37808bf 100644 +index c0ab25c..9d49f8f 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -176,16 +176,24 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, @@ -28548,7 +29839,7 @@ index d47a53b..61154c2 100644 INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); INIT_WORK(&dev_priv->error_work, i915_error_work_func); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index daa5743..c0757a9 100644 +index 9ec9755..6d1cf2d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2230,7 +2230,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, @@ -31226,7 +32517,7 @@ index 4daf9e5..b8d1d0f 100644 .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c -index 31c2dc2..a2de7a6 100644 +index 1ce84ed..0fdd40a 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1589,7 +1589,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) @@ -31370,10 +32661,10 @@ index 8e91321..fd17aef 100644 "start=%llu, len=%llu, dev_size=%llu", dm_device_name(ti->table->md), bdevname(bdev, b), diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c -index 59c4f04..4c7b661 100644 +index 237571a..fb6d19b 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c -@@ -431,7 +431,7 @@ static int init_pmd(struct dm_pool_metadata *pmd, +@@ -432,7 +432,7 @@ static int init_pmd(struct dm_pool_metadata *pmd, pmd->info.tm = tm; pmd->info.levels = 2; @@ -31382,7 +32673,7 @@ index 59c4f04..4c7b661 100644 pmd->info.value_type.size = sizeof(__le64); pmd->info.value_type.inc = data_block_inc; pmd->info.value_type.dec = data_block_dec; -@@ -450,7 +450,7 @@ static int init_pmd(struct dm_pool_metadata *pmd, +@@ -451,7 +451,7 @@ static int init_pmd(struct dm_pool_metadata *pmd, pmd->bl_info.tm = tm; pmd->bl_info.levels = 1; @@ -31925,6 +33216,35 @@ index 68d1240..46b32eb 100644 {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, {0, } +diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c +index ee0d0b3..7db1a4f 100644 +--- a/drivers/media/video/omap/omap_vout.c ++++ b/drivers/media/video/omap/omap_vout.c +@@ -64,7 +64,12 @@ enum omap_vout_channels { + OMAP_VIDEO2, + }; + +-static struct videobuf_queue_ops video_vbq_ops; ++static struct videobuf_queue_ops video_vbq_ops = { ++ .buf_setup = omap_vout_buffer_setup, ++ .buf_prepare = omap_vout_buffer_prepare, ++ .buf_release = omap_vout_buffer_release, ++ .buf_queue = omap_vout_buffer_queue, ++}; + /* Variables configurable through module params*/ + static u32 video1_numbuffers = 3; + static u32 video2_numbuffers = 3; +@@ -1016,10 +1021,6 @@ static int omap_vout_open(struct file *file) + vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + q = &vout->vbq; +- video_vbq_ops.buf_setup = omap_vout_buffer_setup; +- video_vbq_ops.buf_prepare = omap_vout_buffer_prepare; +- video_vbq_ops.buf_release = omap_vout_buffer_release; +- video_vbq_ops.buf_queue = omap_vout_buffer_queue; + spin_lock_init(&vout->vbq_lock); + + videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev, diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 305e6aa..0143317 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -32755,6 +34075,32 @@ index bf266a0..e024af7 100644 } void be_parse_stats(struct be_adapter *adapter) +diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c +index fb5579a..debdffa 100644 +--- a/drivers/net/ethernet/faraday/ftgmac100.c ++++ b/drivers/net/ethernet/faraday/ftgmac100.c +@@ -30,6 +30,8 @@ + #include <linux/netdevice.h> + #include <linux/phy.h> + #include <linux/platform_device.h> ++#include <linux/interrupt.h> ++#include <linux/irqreturn.h> + #include <net/ip.h> + + #include "ftgmac100.h" +diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c +index a127cb2..0d043cd 100644 +--- a/drivers/net/ethernet/faraday/ftmac100.c ++++ b/drivers/net/ethernet/faraday/ftmac100.c +@@ -30,6 +30,8 @@ + #include <linux/module.h> + #include <linux/netdevice.h> + #include <linux/platform_device.h> ++#include <linux/interrupt.h> ++#include <linux/irqreturn.h> + + #include "ftmac100.h" + diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 61d2bdd..7f1154a 100644 --- a/drivers/net/ethernet/fealnx.c @@ -33130,6 +34476,21 @@ index 1b4658c..a30dabb 100644 struct sis190_private *tp = netdev_priv(dev); struct pci_dev *isa_bridge; u8 reg, tmp8; +diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +index 41e6b33..8e89b0f 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +@@ -139,8 +139,8 @@ void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode) + + writel(value, ioaddr + MMC_CNTRL); + +- pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n", +- MMC_CNTRL, value); ++// pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n", ++// MMC_CNTRL, value); + } + + /* To mask all all interrupts.*/ diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index edfa15d..002bfa9 100644 --- a/drivers/net/ppp/ppp_generic.c @@ -33561,7 +34922,7 @@ index f5ae3c6..7936af3 100644 static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h -index f389b3c..7359e18 100644 +index 1bd8edf..10c6d30 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -605,7 +605,7 @@ struct ath_hw_private_ops { @@ -39729,7 +41090,7 @@ index 79e2ca7..5828ad1 100644 A.out (Assembler.OUTput) is a set of formats for libraries and executables used in the earliest versions of UNIX. Linux used diff --git a/fs/aio.c b/fs/aio.c -index 969beb0..09fab51 100644 +index 67e4b90..fbb09dc 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -119,7 +119,7 @@ static int aio_setup_ring(struct kioctx *ctx) @@ -39741,7 +41102,7 @@ index 969beb0..09fab51 100644 return -EINVAL; nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) / sizeof(struct io_event); -@@ -1461,22 +1461,27 @@ static ssize_t aio_fsync(struct kiocb *iocb) +@@ -1463,22 +1463,27 @@ static ssize_t aio_fsync(struct kiocb *iocb) static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat) { ssize_t ret; @@ -39784,7 +41145,7 @@ index 7ee7ba4..0c61a60 100644 goto out_sig; if (offset > inode->i_sb->s_maxbytes) diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c -index e1fbdee..cd5ea56 100644 +index 6861f61..a25f010 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -60,7 +60,7 @@ static int autofs4_write(struct file *file, const void *addr, int bytes) @@ -39914,7 +41275,7 @@ index a6395bd..f1e376a 100644 (unsigned long) create_aout_tables((char __user *) bprm->p, bprm); #ifdef __alpha__ diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c -index 21ac5ee..dbf63ee 100644 +index 6ff96c6..dbf63ee 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -32,6 +32,7 @@ @@ -40605,15 +41966,6 @@ index 21ac5ee..dbf63ee 100644 fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); } -@@ -1421,7 +1886,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, - for (i = 1; i < view->n; ++i) { - const struct user_regset *regset = &view->regsets[i]; - do_thread_regset_writeback(t->task, regset); -- if (regset->core_note_type && -+ if (regset->core_note_type && regset->get && - (!regset->active || regset->active(t->task, regset))) { - int ret; - size_t size = regset->n * regset->size; @@ -1862,14 +2327,14 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, } @@ -41747,7 +43099,7 @@ index 608c1c3..7d040a8 100644 return rc; } diff --git a/fs/exec.c b/fs/exec.c -index 3625464..04855f9 100644 +index 3625464..cdeecdb 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -55,12 +55,28 @@ @@ -41815,11 +43167,11 @@ index 3625464..04855f9 100644 return page; +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+ // only allow 1MB for argv+env on suid/sgid binaries ++ // only allow 512KB for argv+env on suid/sgid binaries + // to prevent easy ASLR exhaustion + if (((bprm->cred->euid != current_euid()) || + (bprm->cred->egid != current_egid())) && -+ (size > (1024 * 1024))) { ++ (size > (512 * 1024))) { + put_page(page); + return NULL; + } @@ -41847,7 +43199,7 @@ index 3625464..04855f9 100644 + +#ifdef CONFIG_PAX_RANDUSTACK + if (randomize_va_space) -+ bprm->p ^= (pax_get_random_long() & ~15) & ~PAGE_MASK; ++ bprm->p ^= random32() & ~PAGE_MASK; +#endif + return 0; @@ -42072,18 +43424,36 @@ index 3625464..04855f9 100644 bprm->unsafe |= LSM_UNSAFE_SHARE; } else { res = -EAGAIN; -@@ -1442,6 +1475,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) +@@ -1442,6 +1475,28 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) EXPORT_SYMBOL(search_binary_handler); +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+static atomic64_unchecked_t global_exec_counter = ATOMIC64_INIT(0); ++static DEFINE_PER_CPU(u64, exec_counter); ++static int __init init_exec_counters(void) ++{ ++ unsigned int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ per_cpu(exec_counter, cpu) = (u64)cpu; ++ } ++ ++ return 0; ++} ++early_initcall(init_exec_counters); ++static inline void increment_exec_counter(void) ++{ ++ BUILD_BUG_ON(NR_CPUS > (1 << 16)); ++ current->exec_id = this_cpu_add_return(exec_counter, 1 << 16); ++} ++#else ++static inline void increment_exec_counter(void) {} +#endif + /* * sys_execve() executes a new program. */ -@@ -1450,6 +1487,11 @@ static int do_execve_common(const char *filename, +@@ -1450,6 +1505,11 @@ static int do_execve_common(const char *filename, struct user_arg_ptr envp, struct pt_regs *regs) { @@ -42095,7 +43465,7 @@ index 3625464..04855f9 100644 struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; -@@ -1457,6 +1499,8 @@ static int do_execve_common(const char *filename, +@@ -1457,6 +1517,8 @@ static int do_execve_common(const char *filename, int retval; const struct cred *cred = current_cred(); @@ -42104,7 +43474,7 @@ index 3625464..04855f9 100644 /* * We move the actual failure in case of RLIMIT_NPROC excess from * set*uid() to execve() because too many poorly written programs -@@ -1497,12 +1541,27 @@ static int do_execve_common(const char *filename, +@@ -1497,12 +1559,27 @@ static int do_execve_common(const char *filename, if (IS_ERR(file)) goto out_unmark; @@ -42132,24 +43502,10 @@ index 3625464..04855f9 100644 retval = bprm_mm_init(bprm); if (retval) goto out_file; -@@ -1532,11 +1591,46 @@ static int do_execve_common(const char *filename, +@@ -1519,24 +1596,65 @@ static int do_execve_common(const char *filename, if (retval < 0) goto out; -+ if (!gr_tpe_allow(file)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ if (gr_check_crash_exec(file)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); -+ -+ gr_handle_exec_args(bprm, argv); -+ +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim)); @@ -42157,12 +43513,50 @@ index 3625464..04855f9 100644 + get_file(file); + current->exec_file = file; +#endif ++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP ++ /* limit suid stack to 8MB ++ we saved the old limits above and will restore them if this exec fails ++ */ ++ if (((bprm->cred->euid != current_euid()) || (bprm->cred->egid != current_egid())) && ++ (old_rlim[RLIMIT_STACK].rlim_cur > (8 * 1024 * 1024))) ++ current->signal->rlim[RLIMIT_STACK].rlim_cur = 8 * 1024 * 1024; ++#endif ++ ++ if (!gr_tpe_allow(file)) { ++ retval = -EACCES; ++ goto out_fail; ++ } ++ ++ if (gr_check_crash_exec(file)) { ++ retval = -EACCES; ++ goto out_fail; ++ } + + retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt, + bprm->unsafe); + if (retval < 0) + goto out_fail; + + retval = copy_strings_kernel(1, &bprm->filename, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; + + bprm->exec = bprm->p; + retval = copy_strings(bprm->envc, envp, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; + + retval = copy_strings(bprm->argc, argv, bprm); + if (retval < 0) +- goto out; ++ goto out_fail; ++ ++ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); ++ ++ gr_handle_exec_args(bprm, argv); + retval = search_binary_handler(bprm,regs); if (retval < 0) - goto out; @@ -42173,14 +43567,12 @@ index 3625464..04855f9 100644 +#endif /* execve succeeded */ -+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP -+ current->exec_id = atomic64_inc_return_unchecked(&global_exec_counter); -+#endif + ++ increment_exec_counter(); current->fs->in_exec = 0; current->in_execve = 0; acct_update_integrals(current); -@@ -1545,6 +1639,14 @@ static int do_execve_common(const char *filename, +@@ -1545,6 +1663,14 @@ static int do_execve_common(const char *filename, put_files_struct(displaced); return retval; @@ -42195,7 +43587,7 @@ index 3625464..04855f9 100644 out: if (bprm->mm) { acct_arg_size(bprm, 0); -@@ -1618,7 +1720,7 @@ static int expand_corename(struct core_name *cn) +@@ -1618,7 +1744,7 @@ static int expand_corename(struct core_name *cn) { char *old_corename = cn->corename; @@ -42204,7 +43596,7 @@ index 3625464..04855f9 100644 cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); if (!cn->corename) { -@@ -1715,7 +1817,7 @@ static int format_corename(struct core_name *cn, long signr) +@@ -1715,7 +1841,7 @@ static int format_corename(struct core_name *cn, long signr) int pid_in_pattern = 0; int err = 0; @@ -42213,7 +43605,7 @@ index 3625464..04855f9 100644 cn->corename = kmalloc(cn->size, GFP_KERNEL); cn->used = 0; -@@ -1812,6 +1914,218 @@ out: +@@ -1812,6 +1938,218 @@ out: return ispipe; } @@ -42404,7 +43796,7 @@ index 3625464..04855f9 100644 +#endif +} + -+NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) ++__noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) +{ + if (current->signal->curr_ip) + printk(KERN_ERR "PAX: From %pI4: kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n", @@ -42432,7 +43824,7 @@ index 3625464..04855f9 100644 static int zap_process(struct task_struct *start, int exit_code) { struct task_struct *t; -@@ -2023,17 +2337,17 @@ static void wait_for_dump_helpers(struct file *file) +@@ -2023,17 +2361,17 @@ static void wait_for_dump_helpers(struct file *file) pipe = file->f_path.dentry->d_inode->i_pipe; pipe_lock(pipe); @@ -42455,7 +43847,7 @@ index 3625464..04855f9 100644 pipe_unlock(pipe); } -@@ -2094,7 +2408,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2094,7 +2432,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) int retval = 0; int flag = 0; int ispipe; @@ -42464,7 +43856,7 @@ index 3625464..04855f9 100644 struct coredump_params cprm = { .signr = signr, .regs = regs, -@@ -2109,6 +2423,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2109,6 +2447,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) audit_core_dumps(signr); @@ -42474,7 +43866,7 @@ index 3625464..04855f9 100644 binfmt = mm->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; -@@ -2176,7 +2493,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2176,7 +2517,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) } cprm.limit = RLIM_INFINITY; @@ -42483,7 +43875,7 @@ index 3625464..04855f9 100644 if (core_pipe_limit && (core_pipe_limit < dump_count)) { printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", task_tgid_vnr(current), current->comm); -@@ -2203,6 +2520,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2203,6 +2544,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) } else { struct inode *inode; @@ -42492,7 +43884,7 @@ index 3625464..04855f9 100644 if (cprm.limit < binfmt->min_coredump) goto fail_unlock; -@@ -2246,7 +2565,7 @@ close_fail: +@@ -2246,7 +2589,7 @@ close_fail: filp_close(cprm.file, NULL); fail_dropcount: if (ispipe) @@ -42501,7 +43893,7 @@ index 3625464..04855f9 100644 fail_unlock: kfree(cn.corename); fail_corename: -@@ -2265,7 +2584,7 @@ fail: +@@ -2265,7 +2608,7 @@ fail: */ int dump_write(struct file *file, const void *addr, int nr) { @@ -47392,10 +48784,10 @@ index 23ce927..e274cc1 100644 kfree(s); diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig new file mode 100644 -index 0000000..41df561 +index 0000000..4089e05 --- /dev/null +++ b/grsecurity/Kconfig -@@ -0,0 +1,1075 @@ +@@ -0,0 +1,1078 @@ +# +# grecurity configuration +# @@ -47670,11 +49062,13 @@ index 0000000..41df561 + dangerous sources of information, this option causes reads of sensitive + /proc/<pid> entries where the file descriptor was opened in a different + task than the one performing the read. Such attempts are logged. -+ Finally, this option limits argv/env strings for suid/sgid binaries -+ to 1MB to prevent a complete exhaustion of the stack entropy provided -+ by ASLR. ++ This option also limits argv/env strings for suid/sgid binaries ++ to 512KB to prevent a complete exhaustion of the stack entropy provided ++ by ASLR. Finally, it places an 8MB stack resource limit on suid/sgid ++ binaries to prevent alternative mmap layouts from being abused. ++ + If you use PaX it is essential that you say Y here as it closes up -+ several holes that make full ASLR useless for suid/sgid binaries. ++ several holes that make full ASLR useless locally. + +config GRKERNSEC_BRUTE + bool "Deter exploit bruteforcing" @@ -47814,8 +49208,9 @@ index 0000000..41df561 + Depending upon the option you choose, you can either restrict users to + see only the processes they themselves run, or choose a group that can + view all processes and files normally restricted to root if you choose -+ the "restrict to user only" option. NOTE: If you're running identd as -+ a non-root user, you will have to run it as the group you specify here. ++ the "restrict to user only" option. NOTE: If you're running identd or ++ ntpd as a non-root user, you will have to run it as the group you ++ specify here. + +config GRKERNSEC_PROC_USER + bool "Restrict /proc to user only" @@ -48473,10 +49868,10 @@ index 0000000..41df561 +endmenu diff --git a/grsecurity/Makefile b/grsecurity/Makefile new file mode 100644 -index 0000000..496e60d +index 0000000..1b9afa9 --- /dev/null +++ b/grsecurity/Makefile -@@ -0,0 +1,40 @@ +@@ -0,0 +1,38 @@ +# grsecurity's ACL system was originally written in 2001 by Michael Dalton +# during 2001-2009 it has been completely redesigned by Brad Spengler +# into an RBAC system @@ -48485,9 +49880,7 @@ index 0000000..496e60d +# are copyright Brad Spengler - Open Source Security, Inc., and released +# under the GPL v2 or higher + -+ifndef CONFIG_IA64 +KBUILD_CFLAGS += -Werror -+endif + +obj-y = grsec_chdir.o grsec_chroot.o grsec_exec.o grsec_fifo.o grsec_fork.o \ + grsec_mount.o grsec_sig.o grsec_sysctl.o \ @@ -57705,6 +59098,19 @@ index 1bfcfe5..e04c5c9 100644 +#define L1_CACHE_BYTES (1UL << L1_CACHE_SHIFT) #endif /* __ASM_GENERIC_CACHE_H */ +diff --git a/include/asm-generic/emergency-restart.h b/include/asm-generic/emergency-restart.h +index 0d68a1e..b74a761 100644 +--- a/include/asm-generic/emergency-restart.h ++++ b/include/asm-generic/emergency-restart.h +@@ -1,7 +1,7 @@ + #ifndef _ASM_GENERIC_EMERGENCY_RESTART_H + #define _ASM_GENERIC_EMERGENCY_RESTART_H + +-static inline void machine_emergency_restart(void) ++static inline __noreturn void machine_emergency_restart(void) + { + machine_restart(NULL); + } diff --git a/include/asm-generic/int-l64.h b/include/asm-generic/int-l64.h index 1ca3efc..e3dc852 100644 --- a/include/asm-generic/int-l64.h @@ -57748,6 +59154,18 @@ index 0232ccb..13d9165 100644 }; #undef KMAP_D +diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h +index 9ceb03b..2efbcbd 100644 +--- a/include/asm-generic/local.h ++++ b/include/asm-generic/local.h +@@ -39,6 +39,7 @@ typedef struct + #define local_add_return(i, l) atomic_long_add_return((i), (&(l)->a)) + #define local_sub_return(i, l) atomic_long_sub_return((i), (&(l)->a)) + #define local_inc_return(l) atomic_long_inc_return(&(l)->a) ++#define local_dec_return(l) atomic_long_dec_return(&(l)->a) + + #define local_cmpxchg(l, o, n) atomic_long_cmpxchg((&(l)->a), (o), (n)) + #define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n)) diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h index 725612b..9cc513a 100644 --- a/include/asm-generic/pgtable-nopmd.h @@ -60354,6 +61772,18 @@ index 7939f63..ec6df57 100644 = { .max = ARRAY_SIZE(array), .num = nump, \ .ops = ¶m_ops_##type, \ .elemsize = sizeof(array[0]), .elem = array }; \ +diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h +index a9e6ba4..0f9e29b 100644 +--- a/include/linux/mtd/map.h ++++ b/include/linux/mtd/map.h +@@ -25,6 +25,7 @@ + #include <linux/types.h> + #include <linux/list.h> + #include <linux/string.h> ++#include <linux/kernel.h> + #include <linux/bug.h> + + diff --git a/include/linux/namei.h b/include/linux/namei.h index ffc0213..2c1f2cb 100644 --- a/include/linux/namei.h @@ -60486,6 +61916,18 @@ index b1f8912..c955bff 100644 /* * Protect attach/detach and child_list: +diff --git a/include/linux/personality.h b/include/linux/personality.h +index 8fc7dd1a..c19d89e 100644 +--- a/include/linux/personality.h ++++ b/include/linux/personality.h +@@ -44,6 +44,7 @@ enum { + #define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC | \ + ADDR_NO_RANDOMIZE | \ + ADDR_COMPAT_LAYOUT | \ ++ ADDR_LIMIT_3GB | \ + MMAP_PAGE_ZERO) + + /* diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 77257c9..51d473a 100644 --- a/include/linux/pipe_fs_i.h @@ -60658,30 +62100,6 @@ index e0879a7..a12f962 100644 #include <asm/emergency-restart.h> #endif -diff --git a/include/linux/regset.h b/include/linux/regset.h -index 8abee65..5150fd1 100644 ---- a/include/linux/regset.h -+++ b/include/linux/regset.h -@@ -335,6 +335,9 @@ static inline int copy_regset_to_user(struct task_struct *target, - { - const struct user_regset *regset = &view->regsets[setno]; - -+ if (!regset->get) -+ return -EOPNOTSUPP; -+ - if (!access_ok(VERIFY_WRITE, data, size)) - return -EIO; - -@@ -358,6 +361,9 @@ static inline int copy_regset_from_user(struct task_struct *target, - { - const struct user_regset *regset = &view->regsets[setno]; - -+ if (!regset->set) -+ return -EOPNOTSUPP; -+ - if (!access_ok(VERIFY_READ, data, size)) - return -EIO; - diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 96d465f..b084e05 100644 --- a/include/linux/reiserfs_fs.h @@ -60762,7 +62180,7 @@ index 2148b12..519b820 100644 static inline void anon_vma_merge(struct vm_area_struct *vma, diff --git a/include/linux/sched.h b/include/linux/sched.h -index 1c4f3e9..b4e4851 100644 +index 1c4f3e9..342eb1f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -101,6 +101,7 @@ struct bio_list; @@ -60946,7 +62364,7 @@ index 1c4f3e9..b4e4851 100644 +extern void pax_report_fault(struct pt_regs *regs, void *pc, void *sp); +extern void pax_report_insns(struct pt_regs *regs, void *pc, void *sp); +extern void pax_report_refcount_overflow(struct pt_regs *regs); -+extern NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) ATTRIB_NORET; ++extern __noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type); + /* Future-safe accessor for struct task_struct's cpus_allowed. */ #define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed) @@ -60987,7 +62405,7 @@ index 1c4f3e9..b4e4851 100644 extern void flush_itimer_signals(void); -extern NORET_TYPE void do_group_exit(int); -+extern NORET_TYPE void do_group_exit(int) ATTRIB_NORET; ++extern __noreturn void do_group_exit(int); extern void daemonize(const char *, ...); extern int allow_signal(int); @@ -63630,7 +65048,7 @@ index 58690af..d903d75 100644 /* diff --git a/kernel/exit.c b/kernel/exit.c -index e6e01b9..619f837 100644 +index e6e01b9..0a21b0a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -57,6 +57,10 @@ @@ -63709,6 +65127,15 @@ index e6e01b9..619f837 100644 exit_mm(tsk); if (group_dead) +@@ -1068,7 +1091,7 @@ SYSCALL_DEFINE1(exit, int, error_code) + * Take down every thread in the group. This is called by fatal signals + * as well as by sys_exit_group (below). + */ +-NORET_TYPE void ++__noreturn void + do_group_exit(int exit_code) + { + struct signal_struct *sig = current->signal; diff --git a/kernel/fork.c b/kernel/fork.c index 0acf42c0..9e40e2e 100644 --- a/kernel/fork.c @@ -64409,7 +65836,7 @@ index a4bea97..7a1ae9a 100644 /* * If ret is 0, either ____call_usermodehelper failed and the diff --git a/kernel/kprobes.c b/kernel/kprobes.c -index faa39d1..d7ad37e 100644 +index bc90b87..43c7d8c 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -185,7 +185,7 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) @@ -64430,7 +65857,7 @@ index faa39d1..d7ad37e 100644 kfree(kip); } return 1; -@@ -1953,7 +1953,7 @@ static int __init init_kprobes(void) +@@ -1955,7 +1955,7 @@ static int __init init_kprobes(void) { int i, err = 0; unsigned long offset = 0, size = 0; @@ -64439,7 +65866,7 @@ index faa39d1..d7ad37e 100644 const char *symbol_name; void *addr; struct kprobe_blackpoint *kb; -@@ -2079,7 +2079,7 @@ static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v) +@@ -2081,7 +2081,7 @@ static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v) const char *sym = NULL; unsigned int i = *(loff_t *) v; unsigned long offset = 0; @@ -65860,6 +67287,28 @@ index 78ab24a..332c915 100644 goto out_put_task_struct; } +diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c +index 636af6d..8af70ab 100644 +--- a/kernel/rcutiny.c ++++ b/kernel/rcutiny.c +@@ -46,7 +46,7 @@ + struct rcu_ctrlblk; + static void invoke_rcu_callbacks(void); + static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp); +-static void rcu_process_callbacks(struct softirq_action *unused); ++static void rcu_process_callbacks(void); + static void __call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *rcu), + struct rcu_ctrlblk *rcp); +@@ -186,7 +186,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) + RCU_TRACE(trace_rcu_batch_end(rcp->name, cb_count)); + } + +-static void rcu_process_callbacks(struct softirq_action *unused) ++static void rcu_process_callbacks(void) + { + __rcu_process_callbacks(&rcu_sched_ctrlblk); + __rcu_process_callbacks(&rcu_bh_ctrlblk); diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 764825c..3aa6ac4 100644 --- a/kernel/rcutorture.c @@ -67983,10 +69432,10 @@ index 57d82c6..e9e0552 100644 set_page_address(page, (void *)vaddr); diff --git a/mm/huge_memory.c b/mm/huge_memory.c -index 33141f5..e56bef9 100644 +index 8f005e9..1cb1036 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c -@@ -703,7 +703,7 @@ out: +@@ -704,7 +704,7 @@ out: * run pte_offset_map on the pmd, if an huge pmd could * materialize from under us from a different thread. */ @@ -70753,7 +72202,7 @@ index 7fa41b4..6087460 100644 return count; } diff --git a/mm/nommu.c b/mm/nommu.c -index ee7e57e..cae4e40 100644 +index f59e170..34e2a2b 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -62,7 +62,6 @@ int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */ @@ -70764,7 +72213,7 @@ index ee7e57e..cae4e40 100644 atomic_long_t mmap_pages_allocated; -@@ -829,15 +828,6 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) +@@ -827,15 +826,6 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) EXPORT_SYMBOL(find_vma); /* @@ -70780,7 +72229,7 @@ index ee7e57e..cae4e40 100644 * expand a stack to a given address * - not supported under NOMMU conditions */ -@@ -1557,6 +1547,7 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -1555,6 +1545,7 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, /* most fields are the same, copy all, and then fixup */ *new = *vma; @@ -72510,7 +73959,7 @@ index a5f4e57..910ee6d 100644 /* Okay, we found ICMPv6 header */ diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c -index 5864cc4..121f3a3 100644 +index 5864cc4..121f3a30 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1513,7 +1513,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) @@ -74392,7 +75841,7 @@ index 9ee7164..56c5061 100644 suspend: diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c -index 5a5a776..9600b11 100644 +index 7d84b87..6a69cd9 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -401,7 +401,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, @@ -76374,7 +77823,7 @@ index 5c11312..72742b5 100644 write_hex_cnt = 0; for (i = 0; i < logo_clutsize; i++) { diff --git a/security/Kconfig b/security/Kconfig -index 51bd5a0..eeabc9f 100644 +index 51bd5a0..3a4ebd0 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -4,6 +4,627 @@ @@ -76952,7 +78401,7 @@ index 51bd5a0..eeabc9f 100644 + +config PAX_REFCOUNT + bool "Prevent various kernel object reference counter overflows" -+ depends on GRKERNSEC && (X86 || SPARC64) ++ depends on GRKERNSEC && ((ARM && (CPU_32v6 || CPU_32v6K || CPU_32v7)) || SPARC64 || X86) + help + By saying Y here the kernel will detect and prevent overflowing + various (but not all) kinds of object reference counters. Such @@ -77795,10 +79244,10 @@ index 09d4648..cf234c7 100644 list_add(&s->list, &cs4297a_devs); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h -index 5644711..a2aebc1 100644 +index 71f6744..d8aeae7 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h -@@ -611,7 +611,7 @@ struct hda_bus_ops { +@@ -614,7 +614,7 @@ struct hda_bus_ops { /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_bus *bus); #endif @@ -77807,7 +79256,7 @@ index 5644711..a2aebc1 100644 /* template to pass to the bus constructor */ struct hda_bus_template { -@@ -713,6 +713,7 @@ struct hda_codec_ops { +@@ -716,6 +716,7 @@ struct hda_codec_ops { #endif void (*reboot_notify)(struct hda_codec *codec); }; @@ -77815,7 +79264,7 @@ index 5644711..a2aebc1 100644 /* record for amp information cache */ struct hda_cache_head { -@@ -743,7 +744,7 @@ struct hda_pcm_ops { +@@ -746,7 +747,7 @@ struct hda_pcm_ops { struct snd_pcm_substream *substream); int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec, struct snd_pcm_substream *substream); @@ -77824,7 +79273,7 @@ index 5644711..a2aebc1 100644 /* PCM information for each substream */ struct hda_pcm_stream { -@@ -801,7 +802,7 @@ struct hda_codec { +@@ -804,7 +805,7 @@ struct hda_codec { const char *modelname; /* model name for preset */ /* set by patch */ @@ -77935,10 +79384,10 @@ index a39edcc..1014050 100644 }; diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile new file mode 100644 -index 0000000..469b06a +index 0000000..894c8bf --- /dev/null +++ b/tools/gcc/Makefile -@@ -0,0 +1,21 @@ +@@ -0,0 +1,23 @@ +#CC := gcc +#PLUGIN_SOURCE_FILES := pax_plugin.c +#PLUGIN_OBJECT_FILES := $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES)) @@ -77952,6 +79401,7 @@ index 0000000..469b06a +hostlibs-$(CONFIG_KALLOCSTAT_PLUGIN) += kallocstat_plugin.so +hostlibs-$(CONFIG_PAX_KERNEXEC_PLUGIN) += kernexec_plugin.so +hostlibs-$(CONFIG_CHECKER_PLUGIN) += checker_plugin.so ++hostlibs-y += colorize_plugin.so + +always := $(hostlibs-y) + @@ -77960,6 +79410,7 @@ index 0000000..469b06a +kallocstat_plugin-objs := kallocstat_plugin.o +kernexec_plugin-objs := kernexec_plugin.o +checker_plugin-objs := checker_plugin.o ++colorize_plugin-objs := colorize_plugin.o diff --git a/tools/gcc/checker_plugin.c b/tools/gcc/checker_plugin.c new file mode 100644 index 0000000..d41b5af @@ -78137,6 +79588,159 @@ index 0000000..d41b5af + + return 0; +} +diff --git a/tools/gcc/colorize_plugin.c b/tools/gcc/colorize_plugin.c +new file mode 100644 +index 0000000..ee950d0 +--- /dev/null ++++ b/tools/gcc/colorize_plugin.c +@@ -0,0 +1,147 @@ ++/* ++ * Copyright 2012 by PaX Team <pageexec@freemail.hu> ++ * Licensed under the GPL v2 ++ * ++ * Note: the choice of the license means that the compilation process is ++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, ++ * but for the kernel it doesn't matter since it doesn't link against ++ * any of the gcc libraries ++ * ++ * gcc plugin to colorize diagnostic output ++ * ++ */ ++ ++#include "gcc-plugin.h" ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tree.h" ++#include "tree-pass.h" ++#include "flags.h" ++#include "intl.h" ++#include "toplev.h" ++#include "plugin.h" ++#include "diagnostic.h" ++#include "plugin-version.h" ++#include "tm.h" ++ ++int plugin_is_GPL_compatible; ++ ++static struct plugin_info colorize_plugin_info = { ++ .version = "201203092200", ++}; ++ ++#define GREEN "\033[32m\033[2m" ++#define LIGHTGREEN "\033[32m\033[1m" ++#define YELLOW "\033[33m\033[2m" ++#define LIGHTYELLOW "\033[33m\033[1m" ++#define RED "\033[31m\033[2m" ++#define LIGHTRED "\033[31m\033[1m" ++#define BLUE "\033[34m\033[2m" ++#define LIGHTBLUE "\033[34m\033[1m" ++#define BRIGHT "\033[m\033[1m" ++#define NORMAL "\033[m" ++ ++static diagnostic_starter_fn old_starter; ++static diagnostic_finalizer_fn old_finalizer; ++ ++static void start_colorize(diagnostic_context *context, diagnostic_info *diagnostic) ++{ ++ const char *color; ++ char *newprefix; ++ ++ switch (diagnostic->kind) { ++ case DK_NOTE: ++ color = LIGHTBLUE; ++ break; ++ ++ case DK_PEDWARN: ++ case DK_WARNING: ++ color = LIGHTYELLOW; ++ break; ++ ++ case DK_ERROR: ++ case DK_FATAL: ++ case DK_ICE: ++ case DK_PERMERROR: ++ case DK_SORRY: ++ color = LIGHTRED; ++ break; ++ ++ default: ++ color = NORMAL; ++ } ++ ++ old_starter(context, diagnostic); ++ if (-1 == asprintf(&newprefix, "%s%s" NORMAL, color, context->printer->prefix)) ++ return; ++ pp_destroy_prefix(context->printer); ++ pp_set_prefix(context->printer, newprefix); ++} ++ ++static void finalize_colorize(diagnostic_context *context, diagnostic_info *diagnostic) ++{ ++ old_finalizer(context, diagnostic); ++} ++ ++static void colorize_arm(void) ++{ ++ old_starter = diagnostic_starter(global_dc); ++ old_finalizer = diagnostic_finalizer(global_dc); ++ ++ diagnostic_starter(global_dc) = start_colorize; ++ diagnostic_finalizer(global_dc) = finalize_colorize; ++} ++ ++static unsigned int execute_colorize_rearm(void) ++{ ++ if (diagnostic_starter(global_dc) == start_colorize) ++ return 0; ++ ++ colorize_arm(); ++ return 0; ++} ++ ++struct simple_ipa_opt_pass pass_ipa_colorize_rearm = { ++ .pass = { ++ .type = SIMPLE_IPA_PASS, ++ .name = "colorize_rearm", ++ .gate = NULL, ++ .execute = execute_colorize_rearm, ++ .sub = NULL, ++ .next = NULL, ++ .static_pass_number = 0, ++ .tv_id = TV_NONE, ++ .properties_required = 0, ++ .properties_provided = 0, ++ .properties_destroyed = 0, ++ .todo_flags_start = 0, ++ .todo_flags_finish = 0 ++ } ++}; ++ ++static void colorize_start_unit(void *gcc_data, void *user_data) ++{ ++ colorize_arm(); ++} ++ ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ const char * const plugin_name = plugin_info->base_name; ++ struct register_pass_info colorize_rearm_pass_info = { ++ .pass = &pass_ipa_colorize_rearm.pass, ++ .reference_pass_name = "*free_lang_data", ++ .ref_pass_instance_number = 0, ++ .pos_op = PASS_POS_INSERT_AFTER ++ }; ++ ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; ++ } ++ ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &colorize_plugin_info); ++ register_callback(plugin_name, PLUGIN_START_UNIT, &colorize_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &colorize_rearm_pass_info); ++ return 0; ++} diff --git a/tools/gcc/constify_plugin.c b/tools/gcc/constify_plugin.c new file mode 100644 index 0000000..704a564 @@ -79054,10 +80658,10 @@ index 0000000..008f159 +} diff --git a/tools/gcc/stackleak_plugin.c b/tools/gcc/stackleak_plugin.c new file mode 100644 -index 0000000..4a9b187 +index 0000000..4e82b16 --- /dev/null +++ b/tools/gcc/stackleak_plugin.c -@@ -0,0 +1,326 @@ +@@ -0,0 +1,311 @@ +/* + * Copyright 2011 by the PaX Team <pageexec@freemail.hu> + * Licensed under the GPL v2 @@ -79104,12 +80708,10 @@ index 0000000..4a9b187 +static int track_frame_size = -1; +static const char track_function[] = "pax_track_stack"; +static const char check_function[] = "pax_check_alloca"; -+static tree pax_check_alloca_decl; -+static tree pax_track_stack_decl; +static bool init_locals; + +static struct plugin_info stackleak_plugin_info = { -+ .version = "201203021600", ++ .version = "201203140940", + .help = "track-lowest-sp=nn\ttrack sp in functions whose frame size is at least nn bytes\n" +// "initialize-locals\t\tforcibly initialize all stack frames\n" +}; @@ -79162,20 +80764,29 @@ index 0000000..4a9b187 +static void stackleak_check_alloca(gimple_stmt_iterator *gsi) +{ + gimple check_alloca; -+ tree alloca_size; ++ tree fntype, fndecl, alloca_size; ++ ++ fntype = build_function_type_list(void_type_node, long_unsigned_type_node, NULL_TREE); ++ fndecl = build_fn_decl(check_function, fntype); ++ DECL_ASSEMBLER_NAME(fndecl); // for LTO + + // insert call to void pax_check_alloca(unsigned long size) + alloca_size = gimple_call_arg(gsi_stmt(*gsi), 0); -+ check_alloca = gimple_build_call(pax_check_alloca_decl, 1, alloca_size); ++ check_alloca = gimple_build_call(fndecl, 1, alloca_size); + gsi_insert_before(gsi, check_alloca, GSI_SAME_STMT); +} + +static void stackleak_add_instrumentation(gimple_stmt_iterator *gsi) +{ + gimple track_stack; ++ tree fntype, fndecl; ++ ++ fntype = build_function_type_list(void_type_node, NULL_TREE); ++ fndecl = build_fn_decl(track_function, fntype); ++ DECL_ASSEMBLER_NAME(fndecl); // for LTO + + // insert call to void pax_track_stack(void) -+ track_stack = gimple_build_call(pax_track_stack_decl, 0); ++ track_stack = gimple_build_call(fndecl, 0); + gsi_insert_after(gsi, track_stack, GSI_CONTINUE_LINKING); +} + @@ -79308,27 +80919,6 @@ index 0000000..4a9b187 + return 0; +} + -+static void stackleak_start_unit(void *gcc_data, void *user_dat) -+{ -+ tree fntype; -+ -+ // declare void pax_check_alloca(unsigned long size) -+ fntype = build_function_type_list(void_type_node, long_unsigned_type_node, NULL_TREE); -+ pax_check_alloca_decl = build_fn_decl(check_function, fntype); -+ DECL_ASSEMBLER_NAME(pax_check_alloca_decl); // for LTO -+ TREE_PUBLIC(pax_check_alloca_decl) = 1; -+ DECL_EXTERNAL(pax_check_alloca_decl) = 1; -+ DECL_ARTIFICIAL(pax_check_alloca_decl) = 1; -+ -+ // declare void pax_track_stack(void) -+ fntype = build_function_type_list(void_type_node, NULL_TREE); -+ pax_track_stack_decl = build_fn_decl(track_function, fntype); -+ DECL_ASSEMBLER_NAME(pax_track_stack_decl); // for LTO -+ TREE_PUBLIC(pax_track_stack_decl) = 1; -+ DECL_EXTERNAL(pax_track_stack_decl) = 1; -+ DECL_ARTIFICIAL(pax_track_stack_decl) = 1; -+} -+ +int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) +{ + const char * const plugin_name = plugin_info->base_name; @@ -79378,7 +80968,6 @@ index 0000000..4a9b187 + error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + } + -+ register_callback("start_unit", PLUGIN_START_UNIT, &stackleak_start_unit, NULL); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_tree_instrument_pass_info); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_final_pass_info); + diff --git a/3.2.9/4425_grsec_enable_xtpax.patch b/3.2.11/4425_grsec_enable_xtpax.patch index 9735ecf..9735ecf 100644 --- a/3.2.9/4425_grsec_enable_xtpax.patch +++ b/3.2.11/4425_grsec_enable_xtpax.patch diff --git a/3.2.9/4430_grsec-remove-localversion-grsec.patch b/3.2.11/4430_grsec-remove-localversion-grsec.patch index 31cf878..31cf878 100644 --- a/3.2.9/4430_grsec-remove-localversion-grsec.patch +++ b/3.2.11/4430_grsec-remove-localversion-grsec.patch diff --git a/3.2.9/4435_grsec-mute-warnings.patch b/3.2.11/4435_grsec-mute-warnings.patch index e85abd6..e85abd6 100644 --- a/3.2.9/4435_grsec-mute-warnings.patch +++ b/3.2.11/4435_grsec-mute-warnings.patch diff --git a/3.2.9/4440_grsec-remove-protected-paths.patch b/3.2.11/4440_grsec-remove-protected-paths.patch index 5602e8e..637934a 100644 --- a/3.2.9/4440_grsec-remove-protected-paths.patch +++ b/3.2.11/4440_grsec-remove-protected-paths.patch @@ -6,7 +6,7 @@ the filesystem. diff -Naur a/grsecurity/Makefile b/grsecurity/Makefile --- a/grsecurity/Makefile 2011-10-19 20:42:50.000000000 -0400 +++ b/grsecurity/Makefile 2011-10-19 20:45:08.000000000 -0400 -@@ -31,10 +31,4 @@ +@@ -29,10 +29,4 @@ ifdef CONFIG_GRKERNSEC_HIDESYM extra-y := grsec_hidesym.o $(obj)/grsec_hidesym.o: diff --git a/3.2.9/4445_grsec-pax-without-grsec.patch b/3.2.11/4445_grsec-pax-without-grsec.patch index 0ef9311..58301c0 100644 --- a/3.2.9/4445_grsec-pax-without-grsec.patch +++ b/3.2.11/4445_grsec-pax-without-grsec.patch @@ -3,6 +3,9 @@ From: Anthony G. Basile <blueness@gentoo.org> With grsecurity-2.2.2-2.6.32.38-201104171745, the functions pax_report_leak_to_user and pax_report_overflow_from_user in fs/exec.c were consolidated into pax_report_usercopy. This patch has been updated to reflect that change. + +With grsecurity-2.9-2.6.32.58-201203131839, NORET_TYPE has been replaced by __noreturn. +This patch has been updated to reflect that change. -- From: Jory Pratt <anarchy@gentoo.org> Updated patch for kernel 2.6.32 @@ -36,7 +39,7 @@ diff -Naur a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c diff -Naur a/fs/exec.c b/fs/exec.c --- a/fs/exec.c 2011-04-17 19:05:03.000000000 -0400 +++ b/fs/exec.c 2011-04-17 19:20:30.000000000 -0400 -@@ -2024,9 +2024,11 @@ +@@ -2048,9 +2048,11 @@ } up_read(&mm->mmap_sem); } @@ -48,7 +51,7 @@ diff -Naur a/fs/exec.c b/fs/exec.c printk(KERN_ERR "PAX: execution attempt in: %s, %08lx-%08lx %08lx\n", path_fault, start, end, offset); printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, " "PC: %p, SP: %p\n", path_exec, tsk->comm, task_pid_nr(tsk), -@@ -2041,10 +2043,12 @@ +@@ -2065,10 +2067,12 @@ #ifdef CONFIG_PAX_REFCOUNT void pax_report_refcount_overflow(struct pt_regs *regs) { @@ -61,9 +64,9 @@ diff -Naur a/fs/exec.c b/fs/exec.c printk(KERN_ERR "PAX: refcount overflow detected in: %s:%d, uid/euid: %u/%u\n", current->comm, task_pid_nr(current), current_uid(), current_euid()); print_symbol(KERN_ERR "PAX: refcount overflow occured at: %s\n", instruction_pointer(regs)); -@@ -2103,10 +2107,12 @@ +@@ -2127,10 +2131,12 @@ - NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) + __noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) { +#ifdef CONFIG_GRKERNSEC if (current->signal->curr_ip) diff --git a/3.2.9/4450_grsec-kconfig-default-gids.patch b/3.2.11/4450_grsec-kconfig-default-gids.patch index 71b2089..123f877 100644 --- a/3.2.9/4450_grsec-kconfig-default-gids.patch +++ b/3.2.11/4450_grsec-kconfig-default-gids.patch @@ -12,7 +12,7 @@ from shooting themselves in the foot. diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig --- a/grsecurity/Kconfig 2011-12-12 16:54:30.000000000 -0500 +++ b/grsecurity/Kconfig 2011-12-12 16:55:09.000000000 -0500 -@@ -440,7 +440,7 @@ +@@ -443,7 +443,7 @@ config GRKERNSEC_PROC_GID int "GID for special group" depends on GRKERNSEC_PROC_USERGROUP @@ -21,7 +21,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig config GRKERNSEC_PROC_ADD bool "Additional restrictions" -@@ -668,7 +668,7 @@ +@@ -671,7 +671,7 @@ config GRKERNSEC_AUDIT_GID int "GID for auditing" depends on GRKERNSEC_AUDIT_GROUP @@ -30,7 +30,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig config GRKERNSEC_EXECLOG bool "Exec logging" -@@ -872,7 +872,7 @@ +@@ -875,7 +875,7 @@ config GRKERNSEC_TPE_GID int "GID for untrusted users" depends on GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT @@ -39,7 +39,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Setting this GID determines what group TPE restrictions will be *enabled* for. If the sysctl option is enabled, a sysctl option -@@ -881,7 +881,7 @@ +@@ -884,7 +884,7 @@ config GRKERNSEC_TPE_GID int "GID for trusted users" depends on GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT @@ -48,7 +48,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Setting this GID determines what group TPE restrictions will be *disabled* for. If the sysctl option is enabled, a sysctl option -@@ -954,7 +954,7 @@ +@@ -957,7 +957,7 @@ config GRKERNSEC_SOCKET_ALL_GID int "GID to deny all sockets for" depends on GRKERNSEC_SOCKET_ALL @@ -57,7 +57,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Here you can choose the GID to disable socket access for. Remember to add the users you want socket access disabled for to the GID -@@ -975,7 +975,7 @@ +@@ -978,7 +978,7 @@ config GRKERNSEC_SOCKET_CLIENT_GID int "GID to deny client sockets for" depends on GRKERNSEC_SOCKET_CLIENT @@ -66,7 +66,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help Here you can choose the GID to disable client socket access for. Remember to add the users you want client socket access disabled for to -@@ -993,7 +993,7 @@ +@@ -996,7 +996,7 @@ config GRKERNSEC_SOCKET_SERVER_GID int "GID to deny server sockets for" depends on GRKERNSEC_SOCKET_SERVER diff --git a/3.2.9/4455_grsec-kconfig-gentoo.patch b/3.2.11/4455_grsec-kconfig-gentoo.patch index 587b7d9..587b7d9 100644 --- a/3.2.9/4455_grsec-kconfig-gentoo.patch +++ b/3.2.11/4455_grsec-kconfig-gentoo.patch diff --git a/3.2.9/4460-grsec-kconfig-proc-user.patch b/3.2.11/4460-grsec-kconfig-proc-user.patch index 1081ed5..2261051 100644 --- a/3.2.9/4460-grsec-kconfig-proc-user.patch +++ b/3.2.11/4460-grsec-kconfig-proc-user.patch @@ -6,7 +6,7 @@ in a different way to avoid bug #366019. This patch should eventually go upstre diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig --- a/grsecurity/Kconfig 2011-06-29 10:02:56.000000000 -0400 +++ b/grsecurity/Kconfig 2011-06-29 10:08:07.000000000 -0400 -@@ -674,7 +674,7 @@ +@@ -677,7 +677,7 @@ config GRKERNSEC_PROC_USER bool "Restrict /proc to user only" @@ -15,7 +15,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig help If you say Y here, non-root users will only be able to view their own processes, and restricts them from viewing network-related information, -@@ -682,7 +682,7 @@ +@@ -685,7 +685,7 @@ config GRKERNSEC_PROC_USERGROUP bool "Allow special group" diff --git a/3.2.9/4465_selinux-avc_audit-log-curr_ip.patch b/3.2.11/4465_selinux-avc_audit-log-curr_ip.patch index cbd978d..af8b7b8 100644 --- a/3.2.9/4465_selinux-avc_audit-log-curr_ip.patch +++ b/3.2.11/4465_selinux-avc_audit-log-curr_ip.patch @@ -28,7 +28,7 @@ Signed-off-by: Lorenzo Hernandez Garcia-Hierro <lorenzo@gnu.org> diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig --- a/grsecurity/Kconfig 2011-04-17 19:25:54.000000000 -0400 +++ b/grsecurity/Kconfig 2011-04-17 19:32:53.000000000 -0400 -@@ -1303,6 +1303,27 @@ +@@ -1306,6 +1306,27 @@ menu "Logging Options" depends on GRKERNSEC diff --git a/3.2.9/4470_disable-compat_vdso.patch b/3.2.11/4470_disable-compat_vdso.patch index 4742d01..4742d01 100644 --- a/3.2.9/4470_disable-compat_vdso.patch +++ b/3.2.11/4470_disable-compat_vdso.patch |