diff --git a/Documentation/core-api/refcount-vs-atomic.rst b/Documentation/core-api/refcount-vs-atomic.rst new file mode 100644 index 0000000000000000000000000000000000000000..976e85adffe8ea4a5820fbea647540208ac357dd --- /dev/null +++ b/Documentation/core-api/refcount-vs-atomic.rst @@ -0,0 +1,168 @@ +=================================== +refcount_t API compared to atomic_t +=================================== + +.. contents:: :local: + +Introduction +============ + +The goal of refcount_t API is to provide a minimal API for implementing +an object's reference counters. While a generic architecture-independent +implementation from lib/refcount.c uses atomic operations underneath, +there are a number of differences between some of the ``refcount_*()`` and +``atomic_*()`` functions with regards to the memory ordering guarantees. +This document outlines the differences and provides respective examples +in order to help maintainers validate their code against the change in +these memory ordering guarantees. + +The terms used through this document try to follow the formal LKMM defined in +tools/memory-model/Documentation/explanation.txt. + +memory-barriers.txt and atomic_t.txt provide more background to the +memory ordering in general and for atomic operations specifically. + +Relevant types of memory ordering +================================= + +.. note:: The following section only covers some of the memory + ordering types that are relevant for the atomics and reference + counters and used through this document. For a much broader picture + please consult memory-barriers.txt document. + +In the absence of any memory ordering guarantees (i.e. fully unordered) +atomics & refcounters only provide atomicity and +program order (po) relation (on the same CPU). It guarantees that +each ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions +are executed in program order on a single CPU. +This is implemented using :c:func:`READ_ONCE`/:c:func:`WRITE_ONCE` and +compare-and-swap primitives. + +A strong (full) memory ordering guarantees that all prior loads and +stores (all po-earlier instructions) on the same CPU are completed +before any po-later instruction is executed on the same CPU. +It also guarantees that all po-earlier stores on the same CPU +and all propagated stores from other CPUs must propagate to all +other CPUs before any po-later instruction is executed on the original +CPU (A-cumulative property). This is implemented using :c:func:`smp_mb`. + +A RELEASE memory ordering guarantees that all prior loads and +stores (all po-earlier instructions) on the same CPU are completed +before the operation. It also guarantees that all po-earlier +stores on the same CPU and all propagated stores from other CPUs +must propagate to all other CPUs before the release operation +(A-cumulative property). This is implemented using +:c:func:`smp_store_release`. + +An ACQUIRE memory ordering guarantees that all post loads and +stores (all po-later instructions) on the same CPU are +completed after the acquire operation. It also guarantees that all +po-later stores on the same CPU must propagate to all other CPUs +after the acquire operation executes. This is implemented using +:c:func:`smp_acquire__after_ctrl_dep`. + +A control dependency (on success) for refcounters guarantees that +if a reference for an object was successfully obtained (reference +counter increment or addition happened, function returned true), +then further stores are ordered against this operation. +Control dependency on stores are not implemented using any explicit +barriers, but rely on CPU not to speculate on stores. This is only +a single CPU relation and provides no guarantees for other CPUs. + + +Comparison of functions +======================= + +case 1) - non-"Read/Modify/Write" (RMW) ops +------------------------------------------- + +Function changes: + + * :c:func:`atomic_set` --> :c:func:`refcount_set` + * :c:func:`atomic_read` --> :c:func:`refcount_read` + +Memory ordering guarantee changes: + + * none (both fully unordered) + + +case 2) - increment-based ops that return no value +-------------------------------------------------- + +Function changes: + + * :c:func:`atomic_inc` --> :c:func:`refcount_inc` + * :c:func:`atomic_add` --> :c:func:`refcount_add` + +Memory ordering guarantee changes: + + * none (both fully unordered) + +case 3) - decrement-based RMW ops that return no value +------------------------------------------------------ + +Function changes: + + * :c:func:`atomic_dec` --> :c:func:`refcount_dec` + +Memory ordering guarantee changes: + + * fully unordered --> RELEASE ordering + + +case 4) - increment-based RMW ops that return a value +----------------------------------------------------- + +Function changes: + + * :c:func:`atomic_inc_not_zero` --> :c:func:`refcount_inc_not_zero` + * no atomic counterpart --> :c:func:`refcount_add_not_zero` + +Memory ordering guarantees changes: + + * fully ordered --> control dependency on success for stores + +.. note:: We really assume here that necessary ordering is provided as a + result of obtaining pointer to the object! + + +case 5) - generic dec/sub decrement-based RMW ops that return a value +--------------------------------------------------------------------- + +Function changes: + + * :c:func:`atomic_dec_and_test` --> :c:func:`refcount_dec_and_test` + * :c:func:`atomic_sub_and_test` --> :c:func:`refcount_sub_and_test` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + ACQUIRE ordering on success + + +case 6) other decrement-based RMW ops that return a value +--------------------------------------------------------- + +Function changes: + + * no atomic counterpart --> :c:func:`refcount_dec_if_one` + * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + control dependency + +.. note:: :c:func:`atomic_add_unless` only provides full order on success. + + +case 7) - lock-based RMW +------------------------ + +Function changes: + + * :c:func:`atomic_dec_and_lock` --> :c:func:`refcount_dec_and_lock` + * :c:func:`atomic_dec_and_mutex_lock` --> :c:func:`refcount_dec_and_mutex_lock` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + control dependency + hold + :c:func:`spin_lock` on success diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 2ed34baeae35542018837169322fc2ba2dabcc81..a1abf22752f2dbddfcf7cdb44bbcde8b0306f5da 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -26,6 +26,7 @@ Required properties: - qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF - qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem - qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs. +- qcom,wcnss-vadc: VADC handle for battery voltage notification APIs. - pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt - pinctrl-names : Names corresponding to the numbered pinctrl states - clocks: from common clock binding: handle to xo and rf_clk clocks. @@ -42,6 +43,9 @@ according to the ponto HW version - qcom,is-pronto-v3: boolean flag to determine the pronto hardware version in use. subsequently correct workqueue will be used by DXE engine to push frames in TX data path and correct voting to RPM will be decided for booting. +- qcom,is-pronto-v4: boolean flag to determine the pronto hardware version +in use. subsequently correct workqueue will be used by DXE engine to push frames +in TX data path. - qcom,wcnss-pm : Power manager related parameter for LDO configuration. @@ -51,7 +55,12 @@ in TX data path and correct voting to RPM will be decided for booting. 1 - WCN RPM power collapse enabled 1 - WCN standalone power collapse enabled 6 - GPIO strength value - +- qcom,wlan-indication-enabled: boolean flag to determine if WLAN indication-LED +will be turned on/off when WLAN is enabled/disabled respectively. +- qcom,has-vsys-adc-channel: boolean flag to determine which ADC HW channel need +to use for VBATT feature. +- qcom,pc-disable-latency: is a configurable value to configure +pc disable latency value. Example: diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 0706d32a61e6fc0fafbbe9a975d095d5e37e95f7..cf0444857e0d8c73d6903d97eb9cf61088d7ee09 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -344,25 +344,38 @@ prototypes: locking rules: - file_lock_lock may block + inode->i_lock may block fl_copy_lock: yes no fl_release_private: maybe no ----------------------- lock_manager_operations --------------------------- prototypes: int (*lm_compare_owner)(struct file_lock *, struct file_lock *); + unsigned long (*lm_owner_key)(struct file_lock *); void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, struct file_lock *, int); void (*lm_break)(struct file_lock *); /* break_lease callback */ int (*lm_change)(struct file_lock **, int); locking rules: - file_lock_lock may block -lm_compare_owner: yes no -lm_notify: yes no -lm_grant: no no -lm_break: yes no -lm_change yes no + + inode->i_lock blocked_lock_lock may block +lm_compare_owner: yes[1] maybe no +lm_owner_key yes[1] yes no +lm_notify: yes yes no +lm_grant: no no no +lm_break: yes no no +lm_change yes no no + +[1]: ->lm_compare_owner and ->lm_owner_key are generally called with +*an* inode->i_lock held. It may not be the i_lock of the inode +associated with either file_lock argument! This is the case with deadlock +detection, since the code has to chase down the owners of locks that may +be entirely unrelated to the one on which the lock is being acquired. +For deadlock detection however, the blocked_lock_lock is also held. The +fact that these locks are held ensures that the file_locks do not +disappear out from under you while doing the comparison or generating an +owner key. --------------------------- buffer_head ----------------------------------- prototypes: diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index a1e2e0dda9074d1d8a3102df3488a8a5f29cfb17..a285660a7bdfae944087c22e62472ae63f48ad4a 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt @@ -171,23 +171,19 @@ output must be passed to the seq_file code. Some utility functions have been defined which make this task easy. Most code will simply use seq_printf(), which works pretty much like -printk(), but which requires the seq_file pointer as an argument. It is -common to ignore the return value from seq_printf(), but a function -producing complicated output may want to check that value and quit if -something non-zero is returned; an error return means that the seq_file -buffer has been filled and further output will be discarded. +printk(), but which requires the seq_file pointer as an argument. For straight character output, the following functions may be used: - int seq_putc(struct seq_file *m, char c); - int seq_puts(struct seq_file *m, const char *s); - int seq_escape(struct seq_file *m, const char *s, const char *esc); + seq_putc(struct seq_file *m, char c); + seq_puts(struct seq_file *m, const char *s); + seq_escape(struct seq_file *m, const char *s, const char *esc); The first two output a single character and a string, just like one would expect. seq_escape() is like seq_puts(), except that any character in s which is in the string esc will be represented in octal form in the output. -There is also a pair of functions for printing filenames: +There are also a pair of functions for printing filenames: int seq_path(struct seq_file *m, struct path *path, char *esc); int seq_path_root(struct seq_file *m, struct path *path, @@ -200,6 +196,14 @@ root is desired, it can be used with seq_path_root(). Note that, if it turns out that path cannot be reached from root, the value of root will be changed in seq_file_root() to a root which *does* work. +A function producing complicated output may want to check + bool seq_has_overflowed(struct seq_file *m); +and avoid further seq_ calls if true is returned. + +A true return from seq_has_overflowed means that the seq_file buffer will +be discarded and the seq_show function will attempt to allocate a larger +buffer and retry printing. + Making it all work diff --git a/MAINTAINERS b/MAINTAINERS index 4c67775b861725a1c3194bb2e7dced3a59266d9f..79ea69fe28890e685f7501ff3ec91941c38734e8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4955,6 +4955,11 @@ F: arch/powerpc/platforms/pasemi/ F: drivers/*/*pasemi* F: drivers/*/*/*pasemi* +LINUX KERNEL DUMP TEST MODULE (LKDTM) +M: Kees Cook +S: Maintained +F: drivers/misc/lkdtm/* + LINUX SECURITY MODULE (LSM) FRAMEWORK M: Chris Wright L: linux-security-module@vger.kernel.org diff --git a/Makefile b/Makefile index e8ef2f1bf0c6ec8ce7c8a91022c59d8fc6c861af..73bcac115ea7069dc1f935dfc569dda4c5aef0ff 100644 --- a/Makefile +++ b/Makefile @@ -347,7 +347,7 @@ AFLAGS_MODULE = LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = -CFLAGS_GCOV = -fprofile-arcs -ftest-coverage +CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im # Use USERINCLUDE when you must reference the UAPI directories only. @@ -407,8 +407,9 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve # Files to ignore in find ... statements -RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \ - -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ + -name CVS -o -name .pc -o -name .hg -o -name .git \) \ + -prune -o export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ --exclude CVS --exclude .pc --exclude .hg --exclude .git @@ -573,11 +574,26 @@ endif # $(dot-config) all: vmlinux ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE -KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) +KBUILD_CFLAGS += -Os else -KBUILD_CFLAGS += -O2 +KBUILD_CFLAGS += -finline-functions -O2 endif +# Disable all maybe-uninitialized warnings +KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) + +# Disable unused-constant-variable warnings +KBUILD_CFLAGS += $(call cc-disable-warning,unused-const-variable,) + +# Disable format-truncation warnings +KBUILD_CFLAGS += $(call cc-disable-warning,format-truncation,) + +# Needed to unbreak GCC 7.x and above +KBUILD_CFLAGS += $(call cc-option,-fno-store-merging,) + +# Tell gcc to never replace conditional load with a non-conditional one +KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) + include $(srctree)/arch/$(SRCARCH)/Makefile ifdef CONFIG_READABLE_ASM @@ -596,14 +612,14 @@ endif # Handle stack protector mode. ifdef CONFIG_CC_STACKPROTECTOR_REGULAR - stackp-flag := -fstack-protector + stackp-flag := -fstack-protector --param ssp-buffer-size=4 ifeq ($(call cc-option, $(stackp-flag)),) $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \ -fstack-protector not supported by compiler) endif else ifdef CONFIG_CC_STACKPROTECTOR_STRONG - stackp-flag := -fstack-protector-strong + stackp-flag := -fstack-protector-strong --param ssp-buffer-size=4 ifeq ($(call cc-option, $(stackp-flag)),) $(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \ -fstack-protector-strong not supported by compiler) @@ -615,9 +631,10 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) -# This warning generated too much noise in a regular build. -# Use make W=1 to enable this warning (see scripts/Makefile.build) +# These warnings generated too much noise in a regular build. +# Use make W=1 to enable them (see scripts/Makefile.build) KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) +KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls @@ -676,6 +693,9 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) +# Make sure -fstack-check isn't enabled (like gentoo apparently did) +KBUILD_CFLAGS += $(call cc-option,-fno-stack-check,) + # conserve stack if available KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) @@ -683,8 +703,9 @@ KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) KBUILD_ARFLAGS := $(call ar-option,D) # check for 'asm goto' -ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) +ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y) KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO + KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO endif # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments diff --git a/arch/Kconfig b/arch/Kconfig index 69fcfae907781d3679e47f3b605b9a79b5ce5c3c..c695fe5a82d7cc1addc4bd8f1b84a6dcdb1aa97b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -569,4 +569,13 @@ config OLD_SIGACTION config COMPAT_OLD_SIGACTION bool +config REFCOUNT_FULL + bool "Perform full reference count validation at the expense of speed" + help + Enabling this switches the refcounting infrastructure from a fast + unchecked atomic_t implementation to a fully state checked + implementation, which can be (slightly) slower but provides protections + against various use-after-free conditions that can be used in + security flaw exploits. + source "kernel/gcov/Kconfig" diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi index ede44a88c6c2f094fcee0a779b1ef635d204f5da..e57c40675fbd7a5314fbad25bc9e699d932df2e4 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_common.dtsi @@ -788,7 +788,7 @@ }; &pmi8994_fg { - qcom,hot-bat-decidegc = <550>; + qcom,hot-bat-decidegc = <500>; qcom,warm-bat-decidegc = <450>; qcom,cool-bat-decidegc = <100>; qcom,cold-bat-decidegc = <50>; @@ -1114,6 +1114,21 @@ }; }; +&firmware { + android { + fstab { + android_lta_label: lta-label { + compatible = "android,lta-label"; + dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/LTALabel"; + type = "ext4"; + mnt_flags = "ro,barrier=1"; + fsmgr_flags = "nofail"; + status = "ok"; + }; + }; + }; +}; + &usb3 { qcom,usb_dp-vadc = <&pmi8994_vadc>; qcom,usb_dm-vadc = <&pmi8994_vadc>; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi index fdad49660323902db0e91a468a5a5ac7a34ab580..5d6bbdb7e6c4c363d4d1748923d14d95a4a247e1 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_ivy_common.dtsi @@ -565,7 +565,7 @@ qcom,leds@d800 { qcom,fs-curr-ua = <24000>; somc,calc-curr; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi index 28c758aeb54661756f49fbe7a759e5315780f6b3..133d2a423ca70706a59ad9bf52d500ee91a71751 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_r2_common.dtsi @@ -40,6 +40,7 @@ vdd_ana-supply = <&pm8994_l32>; vdd_io-supply = <&pm8994_l32>; fpc,use_fpc2050 = <1>; + fpc,enable-wakeup = <1>; spi-max-frequency = <4800000>; spi-qup-id = <1>; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi index bd016fa6094f17a5d72abc73acbb549e251affa2..a3de6d12f6b672e78d9a36efacaae914411d75f9 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_common.dtsi @@ -887,7 +887,7 @@ qcom,ilim-ma = <660>; qcom,fs-curr-ua = <24000>; somc,calc-curr; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01 02]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi index ecd18db6504d9b8f263c007cd2a0b18188a05496..789a9e5a377126005a968ddb84054003f8d35b07 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_satsuki_generic.dtsi @@ -37,6 +37,18 @@ pinctrl-1 = <&msm_gpio_29_nfc_sus &msm_gpio_30_sus>; }; }; + + sim_detect { + compatible = "sim-detect"; + interrupt-parent = <&msm_gpio>; + interrupts = <52 0>; + + sim2_det { + label = "sim2-detection"; + gpios = <&msm_gpio 52 0x0>; + debounce-interval = <10>; + }; + }; }; &pm8994_gpios { diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi index 6c090e1d1aca63d336ee179726130c2ba950630d..b9a03477c25827774cc5a369d5200a047e42b457 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_sumire_common.dtsi @@ -868,7 +868,7 @@ qcom,ilim-ma = <660>; qcom,fs-curr-ua = <24000>; somc,calc-curr; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi b/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi index dd1ee18df8c6984d641498e34c768482b6188cdc..5a61ab6365e9a6639f346da2fd8136fa8b5f1e4b 100644 --- a/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-kitakami_suzuran_common.dtsi @@ -883,7 +883,7 @@ qcom,ilim-ma = <660>; qcom,fs-curr-ua = <25000>; somc,bl-scale-enabled; - somc,init-br = <800>; + somc,init-br = <128>; somc-s1,br-power-save = <131>; qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/msm8994-v2.dtsi b/arch/arm/boot/dts/qcom/msm8994-v2.dtsi index 9c078cceabaa1830549860496b4405301647503d..add83045413a45c517eb8aab741d327f1af07967 100644 --- a/arch/arm/boot/dts/qcom/msm8994-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-v2.dtsi @@ -81,7 +81,9 @@ < 864000000 8>, < 960000000 9>, < 1248000000 10>, - < 1344000000 11>; + < 1344000000 11>, + < 1478400000 12>, + < 1555200000 13>; qcom,a57-speedbin0-v0 = < 0 0>, < 384000000 5>, @@ -93,7 +95,11 @@ < 1248000000 9>, < 1344000000 10>, < 1440000000 11>, - < 1536000000 12>; + < 1536000000 12>, + < 1632000000 13>, + < 1728000000 14>, + < 1824000000 16>, + < 1958400000 17>; qcom,a57-speedbin1-v0 = < 0 0>, < 384000000 5>, @@ -105,7 +111,9 @@ < 1248000000 9>, < 1344000000 10>, < 1440000000 11>, - < 1536000000 12>; + < 1536000000 12>, + < 1632000000 13>, + < 1766400000 15>; qcom,cci-speedbin0-v0 = < 0 0>, < 300000000 4>, @@ -136,7 +144,9 @@ < 864000 >, < 960000 >, < 1248000 >, - < 1344000 >; + < 1344000 >, + < 1478400 >, + < 1555200 >; qcom,cpufreq-table-4 = < 384000 >, @@ -148,7 +158,11 @@ < 1248000 >, < 1344000 >, < 1440000 >, - < 1536000 >; + < 1536000 >, + < 1632000 >, + < 1728000 >, + < 1824000 >, + < 1958400 >; }; &devfreq_cpufreq { @@ -162,7 +176,9 @@ < 864000 4066 >, < 960000 5928 >, < 1248000 7904 >, - < 1344000 9887 >; + < 1344000 9887 >, + < 1478400 11863 >, + < 1555200 11863 >; cpu-to-dev-map-4 = < 384000 1525 >, < 480000 2288 >, @@ -173,7 +189,11 @@ < 1248000 5928 >, < 1344000 7904 >, < 1440000 7904 >, - < 1536000 7904 >; + < 1536000 7904 >, + < 1632000 9887 >, + < 1728000 9887 >, + < 1824000 11863 >, + < 1958400 11863 >; }; mincpubw-cpufreq { @@ -187,7 +207,9 @@ < 864000 1525 >, < 960000 1525 >, < 1248000 1525 >, - < 1344000 1525 >; + < 1344000 1525 >, + < 1478400 1525 >, + < 1555200 1525 >; cpu-to-dev-map-4 = < 384000 1525 >, < 480000 1525 >, @@ -198,7 +220,11 @@ < 1248000 1525 >, < 1344000 1525 >, < 1440000 1525 >, - < 1536000 1525 >; + < 1536000 1525 >, + < 1632000 1525 >, + < 1728000 1525 >, + < 1824000 1525 >, + < 1958400 7904 >; }; cci-cpufreq { @@ -211,7 +237,9 @@ < 864000 537600 >, < 960000 600000 >, < 1248000 729600 >, - < 1344000 787200 >; + < 1344000 787200 >, + < 1478400 787200 >, + < 1555200 787200 >; cpu-to-dev-map-4 = < 384000 300000 >, < 480000 300000 >, @@ -222,7 +250,11 @@ < 1248000 729600 >, < 1344000 729600 >, < 1440000 729600 >, - < 1536000 787200 >; + < 1536000 787200 >, + < 1632000 787200 >, + < 1728000 787200 >, + < 1824000 787200 >, + < 1958400 787200 >; }; }; diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index 91b99abe7a95c114be0d3b628fb8b8d09f781c74..d998c86bc9f393c66a9bdcb6e803aee0a2e14662 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -9,8 +9,6 @@ #define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -#define kmap_prot PAGE_KERNEL - #define flush_cache_kmaps() \ do { \ if (cache_is_vivt()) \ @@ -19,9 +17,6 @@ extern pte_t *pkmap_page_table; -extern void *kmap_high(struct page *page); -extern void kunmap_high(struct page *page); - /* * The reason for kmap_high_get() is to ensure that the currently kmap'd * page usage count does not decrease to zero while we're using its @@ -62,10 +57,6 @@ static inline void *kmap_high_get(struct page *page) * when CONFIG_HIGHMEM is not set. */ #ifdef CONFIG_HIGHMEM -extern void *kmap(struct page *page); -extern void kunmap(struct page *page); -extern void *kmap_atomic(struct page *page); -extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(const void *ptr); #endif diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 87c010557b1d45fbf42d638333636f3fa24a48ea..8a1c2c8a1a64a5f4b6a91bf4efead289067a3617 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -232,6 +232,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { switch (cmd) { + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: case F_GETLK64: case F_SETLK64: case F_SETLKW64: diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index d6f9ee8f10b795f7aadf7a48a7358d26cb30d3c7..cabcaddc03ff9118a8fd6ca965b312fa413493be 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -19,35 +19,14 @@ #include #include "mm.h" -void *kmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} -EXPORT_SYMBOL(kmap); - -void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); -void *kmap_atomic(struct page *page) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned int idx; unsigned long vaddr; void *kmap; int type; - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - #ifdef CONFIG_DEBUG_HIGHMEM /* * There is no cache coherency issue when non VIVT, so force the @@ -78,12 +57,13 @@ void *kmap_atomic(struct page *page) * with the new mapping. */ set_top_pte(vaddr, mk_pte(page, kmap_prot)); + //set_fixmap_pte(idx, mk_pte(page, prot)); return (void *)vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int idx, type; @@ -105,15 +85,15 @@ void __kunmap_atomic(void *kvaddr) /* this address was obtained through kmap_high_get() */ kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)])); } - pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); void *kmap_atomic_pfn(unsigned long pfn) { unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1a107383436fe16e71ef5730811880e8a00fb7ce..f678b9a02b83f4b3f0e944d96f1804538d0ce598 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -30,6 +30,7 @@ config ARM64 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select HARDIRQS_SW_RESEND + select HAVE_ARCH_HARDENED_USERCOPY select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS diff --git a/arch/arm64/configs/diffconfig/ivy_diffconfig b/arch/arm64/configs/diffconfig/ivy_diffconfig index fcf91fba741b8d5140593cd432f1d8d708879495..9371a74cd0d6f9bd7a09a227ea7a8e45db06ac1f 100644 --- a/arch/arm64/configs/diffconfig/ivy_diffconfig +++ b/arch/arm64/configs/diffconfig/ivy_diffconfig @@ -15,4 +15,10 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y # CONFIG_CNSS is not set -# CONFIG_CNSS_PCI is not set \ No newline at end of file +# CONFIG_CNSS_PCI is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig b/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig index 478f7ed52b8ed238adceda6f586b531fa9276b23..8d58fc97a159e0da6941766a8d6200ab098d05bd 100644 --- a/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/ivy_dsds_diffconfig @@ -13,4 +13,10 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y # CONFIG_CNSS is not set -# CONFIG_CNSS_PCI is not set \ No newline at end of file +# CONFIG_CNSS_PCI is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/karin_diffconfig b/arch/arm64/configs/diffconfig/karin_diffconfig index 5db93b663037183697158e8119e16b8ebc6c268b..8a7470dfc1e1c13dfe5fc584da01c542da5dc38b 100644 --- a/arch/arm64/configs/diffconfig/karin_diffconfig +++ b/arch/arm64/configs/diffconfig/karin_diffconfig @@ -9,3 +9,9 @@ CONFIG_PLUG_DET_TH_MID=y CONFIG_TOUCHSCREEN_MAXIM_STI=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/karin_windy_diffconfig b/arch/arm64/configs/diffconfig/karin_windy_diffconfig index dbab55d34f796aaf8aada5b3296a4af19ffddc82..c8b5359bd8e81871fb56c3ea38910b9ae96001d5 100644 --- a/arch/arm64/configs/diffconfig/karin_windy_diffconfig +++ b/arch/arm64/configs/diffconfig/karin_windy_diffconfig @@ -8,3 +8,14 @@ CONFIG_NFC_PN547=y CONFIG_TOUCHSCREEN_MAXIM_STI=y # CONFIG_CNSS is not set # CONFIG_CNSS_PCI is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS is not set +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/satsuki_diffconfig b/arch/arm64/configs/diffconfig/satsuki_diffconfig index 26e4d064abe6e1d6d8f2f369d7eaf90e14b1c1a0..8d9e3caf9267af530c4bd3a3f6d267f0957cda22 100644 --- a/arch/arm64/configs/diffconfig/satsuki_diffconfig +++ b/arch/arm64/configs/diffconfig/satsuki_diffconfig @@ -18,3 +18,9 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig b/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig index d207ba2dff9936fd13b13c6de9e19942001f4a9e..09fab20f298d850873be8ba6a1a3f71cd3a5140d 100644 --- a/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/satsuki_dsds_diffconfig @@ -16,3 +16,9 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/sumire_diffconfig b/arch/arm64/configs/diffconfig/sumire_diffconfig index 4247ee48d5408e410603a2d86cd2cc2a28c1e703..2334f67a80a229abe526af5ab3f7a664609e98b8 100644 --- a/arch/arm64/configs/diffconfig/sumire_diffconfig +++ b/arch/arm64/configs/diffconfig/sumire_diffconfig @@ -18,3 +18,9 @@ CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig b/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig index 4b3398f1adc9dc633161ccc5f3672c897e5be85b..4cdc5601ce29588383841b6bcc53de34353725a6 100644 --- a/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig +++ b/arch/arm64/configs/diffconfig/sumire_dsds_diffconfig @@ -14,3 +14,9 @@ CONFIG_LZ4_DECOMPRESS=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/diffconfig/suzuran_diffconfig b/arch/arm64/configs/diffconfig/suzuran_diffconfig index 737bd7db01297c5d71929ad63d1e3e6d4e1ea9cc..27244563419e89cdc3d7cb5f8748f2be667d77fa 100644 --- a/arch/arm64/configs/diffconfig/suzuran_diffconfig +++ b/arch/arm64/configs/diffconfig/suzuran_diffconfig @@ -15,3 +15,9 @@ CONFIG_LZ4_DECOMPRESS=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MM_OWNER=y +CONFIG_BCMDHD_BCM43455=y +# CONFIG_BCMDHD_PCIE is not set +CONFIG_BCMDHD=y +CONFIG_BCM43455=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" diff --git a/arch/arm64/configs/kitakami_ivy_defconfig b/arch/arm64/configs/kitakami_ivy_defconfig index 7c99523ce1dd7e694ed68a42bbc3884d050f51a0..c80a944e5b6d9e6db8fa878040675e1c2f243123 100644 --- a/arch/arm64/configs/kitakami_ivy_defconfig +++ b/arch/arm64/configs/kitakami_ivy_defconfig @@ -1,131 +1,387 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_IOSCHED_TEST is not set -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y +CONFIG_ARCH_MMAP_RND_BITS=24 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_IVY=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP is not set +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v1-kitakami_ivy_generic msm8994-v2.0-kitakami_ivy_generic msm8994-v2.1-kitakami_ivy_generic" -# CONFIG_COREDUMP is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y # CONFIG_CPU_IDLE_GOV_LADDER is not set # CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_IVY=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SUPPORT_SVS_INTERVAL=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -139,524 +395,297 @@ CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_CPUTIME=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PFT=y +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y CONFIG_POWERKEY_FORCECRASH=y -CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PPPOE=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_LIQUID_DOCK=y +CONFIG_QCOM_NPA_DUMP=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y +CONFIG_QUOTA=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC is not set +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI=y +CONFIG_SDCARD_FS=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y +CONFIG_SDFAT_CHECK_RO_ATTR=y +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY_PFT=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set CONFIG_TABLET_USB_ACECAD=y CONFIG_TABLET_USB_AIPTEK=y CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y +CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y +CONFIG_TUN=y CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y +CONFIG_USB_GADGET=y CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_SUPPORT_SVS_INTERVAL=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_PFT=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y -CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y -CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VFAT_FS_NO_DUALNAMES=y -CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y -CONFIG_SECURITY_NETWORK=y -CONFIG_SECURITY_PFT=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y -CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG is not set +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_karin_defconfig b/arch/arm64/configs/kitakami_karin_defconfig index 4e9eeac476fe02163bbcb7d9db5531672f5f5ad9..eb3366ba50efd757cc49fdce8f2293c56a42e4ab 100644 --- a/arch/arm64/configs/kitakami_karin_defconfig +++ b/arch/arm64/configs/kitakami_karin_defconfig @@ -1,130 +1,375 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y +CONFIG_AD7146=y +CONFIG_AHC=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_KARIN=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v1-kitakami_karin_generic msm8994-v2.0-kitakami_karin_generic msm8994-v2.1-kitakami_karin_generic" -# CONFIG_COREDUMP is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y # CONFIG_CPU_IDLE_GOV_LADDER is not set # CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_KSM=y +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_LP855X=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_KARIN=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_TEST=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_TEST=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -138,517 +383,273 @@ CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_CPUTIME=y -CONFIG_QSEECOM=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PLUG_DET_TH_MID=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y CONFIG_POWERKEY_FORCECRASH=y -CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_AD7146=y -CONFIG_SIM_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFS_TEST=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PPPOE=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_LIQUID_DOCK=y +CONFIG_QCOM_NPA_DUMP=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y +CONFIG_QUOTA=y +CONFIG_RADIO_SILABS=y +CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_TEST=y +CONFIG_SCSI=y +CONFIG_SDCARD_FS=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set CONFIG_TABLET_USB_ACECAD=y CONFIG_TABLET_USB_AIPTEK=y CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_MAXIM_STI=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_MAXIM_STI=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_PLUG_DET_TH_MID=y -CONFIG_HIDRAW=y +CONFIG_TUN=y CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y +CONFIG_UID_CPUTIME=y +CONFIG_UID_STAT=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y +CONFIG_USB_GADGET=y CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y -CONFIG_MMC_BLOCK_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_LP855X=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y -CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y -CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VFAT_FS_NO_DUALNAMES=y -CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y -CONFIG_STRICT_MEMORY_RWX=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_karin_windy_defconfig b/arch/arm64/configs/kitakami_karin_windy_defconfig index 212cc4b42ccb7b4608e640aea08225d765edc65c..206be11b10dcacb0dae39b89d848e7c12c16d629 100644 --- a/arch/arm64/configs/kitakami_karin_windy_defconfig +++ b/arch/arm64/configs/kitakami_karin_windy_defconfig @@ -1,130 +1,378 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y +CONFIG_AHC=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_KARIN_WINDY=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -CONFIG_KSM=y -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_PROTOCOL_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="apq8094-v1-kitakami_karin_windy apq8094-v2.0-kitakami_karin_windy apq8094-v2.1-kitakami_karin_windy" -# CONFIG_COREDUMP is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CFG80211=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y # CONFIG_CPU_IDLE_GOV_LADDER is not set # CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y +CONFIG_CRASH_LAST_LOGS=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DRAGONRISE_FF=y +CONFIG_DUMMY=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_E1000E=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_KEYRESET=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_KSM=y +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_LP855X=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_KARIN_WINDY=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_TEST=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_TEST=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -138,514 +386,271 @@ CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y -CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y -CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y -CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_CPUTIME=y -CONFIG_QSEECOM=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y CONFIG_POWERKEY_FORCECRASH=y -CONFIG_RAMDUMP_MEMDESC=y -CONFIG_CRASH_LAST_LOGS=y -CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFS_TEST=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_REQ_CRYPT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_TUN=y -CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PPPOE=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_LIQUID_DOCK=y +CONFIG_QCOM_NPA_DUMP=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y +CONFIG_QUOTA=y +CONFIG_RADIO_SILABS=y +CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_TEST=y +CONFIG_SCSI=y +CONFIG_SDCARD_FS=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TABLET=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set CONFIG_TABLET_USB_ACECAD=y CONFIG_TABLET_USB_AIPTEK=y CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_MAXIM_STI=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_MAXIM_STI=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y +CONFIG_TUN=y CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y +CONFIG_UID_CPUTIME=y +CONFIG_UID_STAT=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y +CONFIG_USB_GADGET=y CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y -CONFIG_MMC_BLOCK_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_LP855X=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y -CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y -CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VFAT_FS_NO_DUALNAMES=y -CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y -CONFIG_STRICT_MEMORY_RWX=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_satsuki_defconfig b/arch/arm64/configs/kitakami_satsuki_defconfig index cba0995c5d2dd50c09243629ea9362acc27a360f..23aaa8a2fe1b496845d773db11297f37d9f40d7d 100644 --- a/arch/arm64/configs/kitakami_satsuki_defconfig +++ b/arch/arm64/configs/kitakami_satsuki_defconfig @@ -1,679 +1,694 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_SATSUKI=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_satsuki_generic msm8994-v2.1-kitakami_satsuki_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BATTERY_BCL=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_satsuki_generic msm8994-v2.1-kitakami_satsuki_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFS_TEST=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y +CONFIG_DRAGONRISE_FF=y CONFIG_DUMMY=y -CONFIG_TUN=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y -CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FPC1145_TEE=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_MISC=y # CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -CONFIG_FPC1145_TEE=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_SATSUKI=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_TEST=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_DDR50_MAX_DTR_LMT=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SUPPORT_SVS_INTERVAL=y +CONFIG_MMC_TEST=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y CONFIG_MSM_CCI=y +CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_DDR50_MAX_DTR_LMT=y -CONFIG_MMC_SUPPORT_SVS_INTERVAL=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y -CONFIG_MMC_BLOCK_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_PWM=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_LIQUID_DOCK=y CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_TEST=y +CONFIG_SCSI=y CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITYFS=y CONFIG_SECURITY_NETWORK=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set +CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_sumire_defconfig b/arch/arm64/configs/kitakami_sumire_defconfig index 9cd120d430fed59f21b37da955c2781eef36e1b3..02582a3ca270193a7ed697971fa3c2ad9d2b4e88 100644 --- a/arch/arm64/configs/kitakami_sumire_defconfig +++ b/arch/arm64/configs/kitakami_sumire_defconfig @@ -1,678 +1,693 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -# CONFIG_IOSCHED_TEST is not set -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_SUMIRE=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_sumire_generic msm8994-v2.1-kitakami_sumire_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM4356=y +CONFIG_BCMDHD_BCM4356=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD_PCIE=y +CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_sumire_generic msm8994-v2.1-kitakami_sumire_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y +CONFIG_DRAGONRISE_FF=y CONFIG_DUMMY=y -CONFIG_TUN=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BCMDHD_PCIE=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_BCMDHD_PREALLOC_PKTIDMAP=y -CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD=y -CONFIG_BCM4356=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_CLD_LL_CORE=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FPC1145_TEE=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_MISC=y # CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -CONFIG_FPC1145_TEE=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_SUMIRE=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_DDR50_MAX_DTR_LMT=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SUPPORT_SVS_INTERVAL=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y CONFIG_MSM_CCI=y +CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y CONFIG_MSM_EEPROM=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_FD=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y +CONFIG_MSM_KGSL=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SPM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_MSM_TZ_LOG=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y -CONFIG_MSM_FD=y CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y -CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_DDR50_MAX_DTR_LMT=y -CONFIG_MMC_SUPPORT_SVS_INTERVAL=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_NO_HZ=y CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y +CONFIG_OOPS_LOG_BUFFER=y +CONFIG_OOPS_LOG_BUF_SHIFT=14 +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set CONFIG_PFT=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_CLK_SDCC2_CLK_SRC_40MHZ=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y -CONFIG_MSM_RUN_QUEUE_STATS=y -CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y -CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y -CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y +CONFIG_PWM=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_LIQUID_DOCK=y CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y -CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI=y CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y -CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y -CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_PFT=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set +CONFIG_TRAY_SHARED_INTERRUPT_DETECT=y +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/configs/kitakami_suzuran_defconfig b/arch/arm64/configs/kitakami_suzuran_defconfig index e77ee7762b0fe5d3871cec2b193244de7aa8073e..2ecb42d385eafee4bd2989d1a23d69d401dbcdd8 100644 --- a/arch/arm64/configs/kitakami_suzuran_defconfig +++ b/arch/arm64/configs/kitakami_suzuran_defconfig @@ -1,672 +1,687 @@ -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_RCU_BOOST=y -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_SCHED_HMP=y -CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set -# CONFIG_PID_NS is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_PANIC_TIMEOUT=5 -# CONFIG_PCI_QUIRKS is not set -CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set -CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_AHC=y +# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set +CONFIG_AMSS_ERR_LOG=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID=y +CONFIG_APSS_CORE_EA=y CONFIG_ARCH_MMAP_RND_BITS=24 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_PARTITION_ADVANCED=y -# CONFIG_IOSCHED_TEST is not set -CONFIG_IOSCHED_BFQ=y -CONFIG_CGROUP_BFQIO=y -CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8994=y CONFIG_ARCH_MSM8994_V1_TLBI_WA=y +CONFIG_ARCH_MSM8994=y +CONFIG_ARCH_MSM=y CONFIG_ARCH_SONY_KITAKAMI=y -CONFIG_MACH_SONY_SUZURAN=y -CONFIG_PCI_MSM=y CONFIG_ARM64_A57_ERRATA_832075=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_PREEMPT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM_CCI=y CONFIG_ARMV7_COMPAT=y -# CONFIG_KSM is not set -CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_ASHMEM=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ATH_CARDS=y +CONFIG_AUDIT=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_suzuran_generic msm8994-v2.1-kitakami_suzuran_generic" -# CONFIG_COREDUMP is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -# CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -# CONFIG_WAKEUP_IRQ_DEBUG=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_BOOST=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=y -CONFIG_XFRM_RFC_4868_TRUNCATION=y -CONFIG_INET=y -CONFIG_WIREGUARD=y -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=y -CONFIG_NF_CONNTRACK_FTP=y -CONFIG_NF_CONNTRACK_H323=y -CONFIG_NF_CONNTRACK_IRC=y -CONFIG_NF_CONNTRACK_NETBIOS_NS=y -CONFIG_NF_CONNTRACK_PPTP=y -CONFIG_NF_CONNTRACK_SANE=y -CONFIG_NF_CONNTRACK_TFTP=y -CONFIG_NF_CT_NETLINK=y -CONFIG_NETFILTER_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y -CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y -CONFIG_NETFILTER_XT_TARGET_TCPMSS=y -CONFIG_NETFILTER_XT_MATCH_COMMENT=y -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y -CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y -CONFIG_NETFILTER_XT_MATCH_ESP=y -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y -CONFIG_NETFILTER_XT_MATCH_HELPER=y -CONFIG_NETFILTER_XT_MATCH_IPRANGE=y -CONFIG_NETFILTER_XT_MATCH_LENGTH=y -CONFIG_NETFILTER_XT_MATCH_LIMIT=y -CONFIG_NETFILTER_XT_MATCH_MAC=y -CONFIG_NETFILTER_XT_MATCH_MARK=y -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -CONFIG_NETFILTER_XT_MATCH_POLICY=y -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y -CONFIG_NETFILTER_XT_MATCH_QUOTA=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y -CONFIG_NETFILTER_XT_MATCH_SOCKET=y -CONFIG_NETFILTER_XT_MATCH_STATE=y -CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -CONFIG_NETFILTER_XT_MATCH_STRING=y -CONFIG_NETFILTER_XT_MATCH_TIME=y -CONFIG_NETFILTER_XT_MATCH_U32=y -CONFIG_NF_CONNTRACK_IPV4=y -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=y -CONFIG_IP_NF_MATCH_ECN=y -CONFIG_IP_NF_MATCH_RPFILTER=y -CONFIG_IP_NF_MATCH_TTL=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y -CONFIG_NF_NAT_IPV4=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_NETMAP=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_RAW=y -CONFIG_IP_NF_SECURITY=y -CONFIG_IP_NF_ARPTABLES=y -CONFIG_IP_NF_ARPFILTER=y -CONFIG_IP_NF_ARP_MANGLE=y -CONFIG_NF_CONNTRACK_IPV6=y -CONFIG_IP6_NF_IPTABLES=y -CONFIG_IP6_NF_MATCH_RPFILTER=y -CONFIG_IP6_NF_FILTER=y -CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y -CONFIG_IP6_NF_MANGLE=y -CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BATTERY_BCL=y +CONFIG_BCM43455=y +CONFIG_BCMDHD_BCM43455=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" +CONFIG_BCMDHD=y +# CONFIG_BCM_WLAN_RAMDUMP=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE=y -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_HTB=y -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_CLS_FW=y -CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_U32=y -CONFIG_NET_CLS_ACT=y -CONFIG_RMNET_DATA=y -CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_SOCKEV_NLMCAST=y -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +CONFIG_BT_BCM43XX=y CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_BNEP=y CONFIG_BT_HIDP=y -# CONFIG_MSM_BT_POWER is not set -CONFIG_BT_BCM43XX=y CONFIG_BT_PROTOCOL_DRIVER=y -CONFIG_LINE_DISCIPLINE_DRIVER=y -CONFIG_V4L2_ANT_DRIVER=y -CONFIG_V4L2_FM_DRIVER=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_RFCOMM=y +CONFIG_BT=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES="msm8994-v2.0-kitakami_suzuran_generic msm8994-v2.1-kitakami_suzuran_generic" +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_CFG80211=y -CONFIG_RFKILL=y -CONFIG_IPC_ROUTER=y -CONFIG_IPC_ROUTER_SECURITY=y -CONFIG_CMA=y -CONFIG_ARM_CCI=y -CONFIG_ZRAM=y -CONFIG_ZRAM_LZ4_COMPRESS=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_UID_STAT=y -CONFIG_UID_SYS_STATS=y -CONFIG_PMI8994_FLASH=y -CONFIG_QSEECOM=y -CONFIG_NFC_PN547=y -CONFIG_TI_DRV2667=y -CONFIG_QCOM_LIQUID_DOCK=y -CONFIG_RAMDUMP_TAGS=y -CONFIG_POWERKEY_FORCECRASH=y -# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BFQIO=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUPS=y +CONFIG_CIFS=y +CONFIG_CLD_LL_CORE=y +CONFIG_CLS_U32_MARK=y +CONFIG_CMA=y +CONFIG_COMPAT=y +# CONFIG_COREDUMP is not set +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE=y +CONFIG_CPUSETS=y CONFIG_CRASH_LAST_LOGS=y -# CONFIG_BCM_WLAN_RAMDUMP=y -CONFIG_LDO_VIBRATOR=y -CONFIG_SIM_DETECT=y -CONFIG_SCSI=y -CONFIG_SCSI_TGT=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XCBC=y +CONFIG_DEBUG_BUS_VOTER=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEVFREQ_SPDM=y +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DMADEVICES=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y +CONFIG_DRAGONRISE_FF=y CONFIG_DUMMY=y -CONFIG_TUN=y +CONFIG_DVB_MPQ_DEMUX=y +CONFIG_DVB_MPQ=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_E1000E=y -CONFIG_RNDIS_IPA=y -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_MPPE=y -CONFIG_PPPOE=y -CONFIG_PPPOLAC=y -CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_USB_USBNET=y -CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -CONFIG_SOMC_WIFI_CONTROL=y -CONFIG_ATH_CARDS=y -CONFIG_WIL6210=y -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" -CONFIG_BCMDHD_SUZURAN=y -CONFIG_BCM43455=y -CONFIG_CLD_LL_CORE=y +CONFIG_ECRYPT_FS=y +CONFIG_EMBEDDED=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="utf8" +CONFIG_FB_MSM_LOGO=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM=y +CONFIG_FB=y +CONFIG_FPC1145_TEE=y +CONFIG_FUSE_FS=y +CONFIG_GENERIC_PHY=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_SYSFS=y +CONFIG_GREENASIA_FF=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HI256=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_ACRUX=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HIDRAW=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_I2C=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_INET=y +CONFIG_INPUT_BU520X1NVX=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_KEYRESET=y -CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_MISC=y # CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_XPAD=y -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=y -CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y -CONFIG_TABLET_USB_HANWANG=y -CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set -CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y -CONFIG_TOUCHSCREEN_CLEARPAD=y -CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y -CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_SECURE_TOUCH=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -CONFIG_INPUT_BU520X1NVX=y -CONFIG_FPC1145_TEE=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y -CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y -CONFIG_SERIAL_MSM_SMD=y -CONFIG_HW_RANDOM_MSM=y -CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MSM_V2=y -CONFIG_SLIMBUS_MSM_NGD=y -CONFIG_SPI=y -CONFIG_SPI_QUP=y -CONFIG_SPI_SPIDEV=y -CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB=y -CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y -CONFIG_PINCTRL_SOMC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_QPNP_PIN=y -CONFIG_SMB349_DUAL_CHARGER=y -CONFIG_SMB135X_CHARGER=y -CONFIG_QPNP_SMBCHARGER_EXTENSION=y -CONFIG_QPNP_SMBCHARGER=y -CONFIG_QPNP_FG_EXTENSION=y -CONFIG_QPNP_FG=y -CONFIG_BATTERY_BCL=y -CONFIG_MSM_BCL_CTL=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_MSM_BCL_SOMC_CTL=y -CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y -CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y -CONFIG_THERMAL=y -CONFIG_THERMAL_TSENS8974=y -CONFIG_LIMITS_MONITOR=y -CONFIG_LIMITS_LITE_HW=y -CONFIG_THERMAL_MONITOR=y -CONFIG_THERMAL_QPNP=y -CONFIG_THERMAL_QPNP_ADC_TM=y -CONFIG_WCD9330_CODEC=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_TPS65132=y -CONFIG_REGULATOR_STUB=y -CONFIG_REGULATOR_RPM_SMD=y -CONFIG_REGULATOR_QPNP=y -CONFIG_REGULATOR_QPNP_LABIBB=y -CONFIG_REGULATOR_SPM=y -CONFIG_REGULATOR_CPR=y -CONFIG_SOMC_LCD_OCP_ENABLED=y -CONFIG_MEDIA_SUPPORT=y +CONFIG_IOMMU_FORCE_4K_MAPPINGS=y +CONFIG_ION_MSM=y +CONFIG_ION=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IPA=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_IPC_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_KERNEL_TEXT_MPU_PROT=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_KEYS=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KSM is not set +CONFIG_LDO_VIBRATOR=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LIMITS_LITE_HW=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LINE_DISCIPLINE_DRIVER=y +CONFIG_LOG_BUF_MAGIC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_MACH_SONY_SUZURAN=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MD=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MHL_BIST=y +CONFIG_MHL_DEVICE_ID=0x07 +CONFIG_MHL_SIMG_SONY=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_CMD_DEBUG=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC=y +CONFIG_MSDOS_FS=y +CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_AVTIMER=y CONFIG_MSMB_CAMERA=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_MSM_BCL_SOMC_CTL=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_BOOT_STATS=y +# CONFIG_MSM_BT_POWER is not set +CONFIG_MSM_BUS_SCALING=y CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y CONFIG_MSM_CCI=y +CONFIG_MSM_CORE_CTL=y +CONFIG_MSM_CPP=y CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y CONFIG_MSM_CSID=y +CONFIG_MSM_CSIPHY=y CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_SONY_CAM_V4L2=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y +CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_FD=y -CONFIG_MSM_VIDC_V4L2=y -CONFIG_DVB_MPQ=y -CONFIG_DVB_MPQ_DEMUX=y -CONFIG_TSPP=y -CONFIG_RADIO_SILABS=y +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_HVC=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MSM_IOMMU_VBIF_CHECK=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_ISPIF=y CONFIG_MSM_KGSL=y -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y -CONFIG_FB=y -CONFIG_FB_MSM=y -CONFIG_FB_MSM_LOGO=y -CONFIG_FB_MSM_MDSS=y -CONFIG_FB_MSM_MDSS_WRITEBACK=y -CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y -CONFIG_FB_MSM_MDSS_HDMI_PANEL=y -CONFIG_MHL_SIMG_SONY=y -CONFIG_MHL_DEVICE_ID=0x07 -CONFIG_MHL_BIST=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_AHC=y -CONFIG_SND_SOC_MSM8994=y -CONFIG_HIDRAW=y -CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_ACRUX=y -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_PRODIKEYS=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=y -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_HOLTEK=y -CONFIG_HID_KEYTOUCH=y -CONFIG_HID_KYE=y -CONFIG_HID_UCLOGIC=y -CONFIG_HID_WALTOP=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=y -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_PICOLCD=y -CONFIG_HID_PRIMAX=y -CONFIG_HID_ROCCAT=y -CONFIG_HID_SAITEK=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SPEEDLINK=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_GREENASIA_FF=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=y -CONFIG_HID_WIIMOTE=y -CONFIG_HID_ZEROPLUS=y -CONFIG_HID_ZYDACRON=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y -CONFIG_USB_EHCI_MSM=y -CONFIG_USB_HOST_EXTRA_NOTIFICATION=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CSVT=y -CONFIG_USB_EHSET_TEST_FIXTURE=y -CONFIG_USB_PHY=y -CONFIG_USB_OTG_WAKELOCK=y -CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y +CONFIG_MSM_OCMEM=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PM=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_QPNP_INT=y CONFIG_MSM_QUSB_PHY=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_DWC3_MSM=y -CONFIG_USB_G_ANDROID=y -CONFIG_USB_MIRRORLINK=y -CONFIG_MMC=y -CONFIG_MMC_PERF_PROFILING=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_MMC_CLKGATE=y -CONFIG_MMC_PARANOID_SD_INIT=y -CONFIG_MMC_CMD_DEBUG=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_QPNP_WLED=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_BACKLIGHT=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_SWITCH=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_QPNP=y -CONFIG_DMADEVICES=y -CONFIG_QCOM_SPS_DMA=y -CONFIG_UIO=y -CONFIG_UIO_MSM_SHAREDMEM=y -CONFIG_STAGING=y -CONFIG_ANDROID=y -CONFIG_ASHMEM=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -CONFIG_ANDROID_TIMED_GPIO=y -CONFIG_ANDROID_LOW_MEMORY_KILLER=y -CONFIG_ANDROID_LOW_MEMORY_KILLER_CONSIDER_SWAP=y -CONFIG_ONESHOT_SYNC=y -CONFIG_ION=y -CONFIG_ION_MSM=y -# CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS is not set -CONFIG_SPS=y -CONFIG_USB_BAM=y -CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_QPNP_POWER_ON=y -CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_QPNP_USB_DETECT=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_AVTIMER=y -CONFIG_PFT=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y -CONFIG_DEBUG_BUS_VOTER=y -CONFIG_PON_SOMC_ORG=y -CONFIG_MSM_MDSS_PLL=y -CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_MSM_IOMMU_V1=y -CONFIG_MSM_IOMMU_VBIF_CHECK=y -CONFIG_IOMMU_FORCE_4K_MAPPINGS=y -CONFIG_DEVFREQ_SPDM=y -CONFIG_PWM=y -CONFIG_PWM_QPNP=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_SENSORS_SSC=y -CONFIG_GENERIC_PHY=y -CONFIG_MSM_EVENT_TIMER=y -CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y -CONFIG_MSM_QMI_INTERFACE=y -CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y -CONFIG_MSM_RPM_SMD=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_SMD=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_MSM_RTB=y CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SCM=y +CONFIG_MSM_SHARED_HEAP_ACCESS=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_SMD=y CONFIG_MSM_SMEM=y -CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SMP2P=y CONFIG_MSM_SPM=y -CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y -CONFIG_MSM_MEMORY_DUMP_V2=y -CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y -CONFIG_MSM_HVC=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y -CONFIG_MSM_PIL=y -CONFIG_MSM_PIL_SSR_GENERIC=y -CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y -CONFIG_MSM_BOOT_STATS=y -CONFIG_MSM_SCM=y -CONFIG_MSM_SHARED_HEAP_ACCESS=y CONFIG_MSM_SYSTEM_HEALTH_MONITOR=y -CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_CORE_CTL=y -CONFIG_MSM_PERFORMANCE=y -CONFIG_QCOM_NPA_DUMP=y -CONFIG_KERNEL_TEXT_MPU_PROT=y -CONFIG_AMSS_ERR_LOG=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_QUOTA=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_VFAT_FS_NO_DUALNAMES=y -CONFIG_SDCARD_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_PSTORE=y -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_RAM=y -CONFIG_CIFS=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MT9M114=y +CONFIG_NAMESPACES=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NETDEVICES=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CONNTRACK=y +CONFIG_NFC_PN547=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT_IPV4=y CONFIG_NLS_ASCII=y -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_SDFAT_SUPPORT_DIR_SYNC=y -CONFIG_SDFAT_CHECK_RO_ATTR=y -# CONFIG_SDFAT_DEBUG is not set CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SYSRQ_SCHED_DEBUG is not set -CONFIG_SCHEDSTATS=y -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_INFO=y -CONFIG_MSM_RTB=y -CONFIG_MSM_RTB_SEPARATE_CPUS=y -CONFIG_CPU_FREQ_SWITCH_PROFILER=y -CONFIG_DYNAMIC_DEBUG=y +CONFIG_NO_HZ=y +CONFIG_ONESHOT_SYNC=y CONFIG_OOPS_LOG_BUFFER=y -CONFIG_LOG_BUF_MAGIC=y CONFIG_OOPS_LOG_BUF_SHIFT=14 -CONFIG_STRICT_DEVMEM=y -CONFIG_KEYS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y -CONFIG_SECURITY=y +CONFIG_PACKET=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PCI_MSM=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PFT=y +# CONFIG_PID_NS is not set +CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_PINCTRL_SOMC=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PMI8994_FLASH=y +CONFIG_PM_RUNTIME=y +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_WAKELOCKS=y +CONFIG_PON_SOMC_ORG=y +CONFIG_POWERKEY_FORCECRASH=y +CONFIG_POWER_RESET_MSM=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP=y +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PROFILING=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE=y +CONFIG_PUBLIC_KEY_ALGO_RSA=y +CONFIG_PWM_QPNP=y +CONFIG_PWM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_LIQUID_DOCK=y +CONFIG_QCOM_NPA_DUMP=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_QMI_ENCDEC=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_FG_EXTENSION=y +CONFIG_QPNP_FG=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_SMBCHARGER_EXTENSION=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_USB_DETECT=y +CONFIG_QSEECOM=y +CONFIG_QUOTA=y +CONFIG_RADIO_SILABS=y +# CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFKILL=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHEDSTATS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_TGT=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI=y +CONFIG_SDCARD_FS=y +CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y +CONFIG_SDFAT_CHECK_RO_ATTR=y +CONFIG_SDFAT_DBG_MSG=y +CONFIG_SDFAT_DEBUG=y +CONFIG_SDFAT_DEFAULT_CODEPAGE=437 +CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_SDFAT_DELAYED_META_DIRTY=y +CONFIG_SDFAT_FS=y +CONFIG_SDFAT_STATISTICS=y +CONFIG_SDFAT_SUPPORT_DIR_SYNC=y +CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" +CONFIG_SDFAT_VIRTUAL_XATTR=y +CONFIG_SECCOMP=y +CONFIG_SECURE_TOUCH=y CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY_PFT=y -CONFIG_LSM_MMAP_MIN_ADDR=4096 -CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEV_QCRYPTO=y -CONFIG_CRYPTO_DEV_QCE=y -CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_PUBLIC_KEY_ALGO_RSA=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y -CONFIG_QMI_ENCDEC=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_SSC=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SIM_DETECT=y +CONFIG_SLIMBUS_MSM_NGD=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB349_DUAL_CHARGER=y +CONFIG_SMP=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC_MSM8994=y +CONFIG_SND_SOC=y +# CONFIG_SND_SPI is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SOMC_WIFI_CONTROL=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_SOUND=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_SPMI=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_SPS=y +CONFIG_STAGING=y +CONFIG_STRICT_DEVMEM=y CONFIG_STRICT_MEMORY_RWX=y -CONFIG_CRYPTO_DEV_SOMC_FIPS_KSCL=y -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ECRYPT_FS=y +CONFIG_SUSPEND_TIME=y +CONFIG_SWAP_CONSIDER_CMA_FREE=y +CONFIG_SWITCH=y +# CONFIG_SYSRQ_SCHED_DEBUG is not set +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL=y +CONFIG_TI_DRV2667=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21 is not set +CONFIG_TSPP=y +CONFIG_TUN=y +CONFIG_UHID=y +CONFIG_UID_STAT=y +CONFIG_UID_SYS_STATS=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_UIO=y +CONFIG_UNIX=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_BAM=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +CONFIG_USB_MIRRORLINK=y +CONFIG_USB_MSM_ACA=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_USB_PHY=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_SERIAL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USE_PINCTRL_IRQ=y +# CONFIG_UTS_NS is not set +CONFIG_V4L2_ANT_DRIVER=y +CONFIG_V4L2_FM_DRIVER=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_VFAT_FS=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_VT is not set +# CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_WCD9330_CODEC=y +CONFIG_WIL6210=y +# CONFIG_WIREGUARD_DEBUG is not set +CONFIG_WIREGUARD=y CONFIG_WTL_ENCRYPTION_FILTER=y -CONFIG_MSM8994_CPU_VOLTAGE_CONTROL=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_XFRM_STATISTICS=y +CONFIG_XFRM_USER=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC=y diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 72674f4c3871502f1079674395eaf2921a50bc10..0cfad81d93f178952406040295be134ae1de25b8 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -54,4 +54,41 @@ #define ESR_EL1_EC_BKPT32 (0x38) #define ESR_EL1_EC_BRK64 (0x3C) +/* ISS field definitions for System instruction traps */ +#define ESR_ELx_SYS64_ISS_RES0_SHIFT 22 +#define ESR_ELx_SYS64_ISS_RES0_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_RES0_SHIFT) +#define ESR_ELx_SYS64_ISS_DIR_MASK 0x1 +#define ESR_ELx_SYS64_ISS_DIR_READ 0x1 +#define ESR_ELx_SYS64_ISS_DIR_WRITE 0x0 + +#define ESR_ELx_SYS64_ISS_RT_SHIFT 5 +#define ESR_ELx_SYS64_ISS_RT_MASK (UL(0x1f) << ESR_ELx_SYS64_ISS_RT_SHIFT) +#define ESR_ELx_SYS64_ISS_CRM_SHIFT 1 +#define ESR_ELx_SYS64_ISS_CRM_MASK (UL(0xf) << ESR_ELx_SYS64_ISS_CRM_SHIFT) +#define ESR_ELx_SYS64_ISS_CRN_SHIFT 10 +#define ESR_ELx_SYS64_ISS_CRN_MASK (UL(0xf) << ESR_ELx_SYS64_ISS_CRN_SHIFT) +#define ESR_ELx_SYS64_ISS_OP1_SHIFT 14 +#define ESR_ELx_SYS64_ISS_OP1_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_OP1_SHIFT) +#define ESR_ELx_SYS64_ISS_OP2_SHIFT 17 +#define ESR_ELx_SYS64_ISS_OP2_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_OP2_SHIFT) +#define ESR_ELx_SYS64_ISS_OP0_SHIFT 20 +#define ESR_ELx_SYS64_ISS_OP0_MASK (UL(0x3) << ESR_ELx_SYS64_ISS_OP0_SHIFT) +#define ESR_ELx_SYS64_ISS_SYS_MASK (ESR_ELx_SYS64_ISS_OP0_MASK | \ + ESR_ELx_SYS64_ISS_OP1_MASK | \ + ESR_ELx_SYS64_ISS_OP2_MASK | \ + ESR_ELx_SYS64_ISS_CRN_MASK | \ + ESR_ELx_SYS64_ISS_CRM_MASK) +#define ESR_ELx_SYS64_ISS_SYS_VAL(op0, op1, op2, crn, crm) \ + (((op0) << ESR_ELx_SYS64_ISS_OP0_SHIFT) | \ + ((op1) << ESR_ELx_SYS64_ISS_OP1_SHIFT) | \ + ((op2) << ESR_ELx_SYS64_ISS_OP2_SHIFT) | \ + ((crn) << ESR_ELx_SYS64_ISS_CRN_SHIFT) | \ + ((crm) << ESR_ELx_SYS64_ISS_CRM_SHIFT)) + +#define ESR_ELx_SYS64_ISS_SYS_OP_MASK (ESR_ELx_SYS64_ISS_SYS_MASK | \ + ESR_ELx_SYS64_ISS_DIR_MASK) + +#define ESR_ELx_SYS64_ISS_SYS_CNTVCT (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + #endif /* __ASM_ESR_H */ diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b6aa1a7fec251a72b028f655523c74236a..77667c30a9ad7cd6804496b8c401ff7496058b54 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -65,7 +65,11 @@ static inline void decode_ctrl_reg(u32 reg, /* Lengths */ #define ARM_BREAKPOINT_LEN_1 0x1 #define ARM_BREAKPOINT_LEN_2 0x3 +#define ARM_BREAKPOINT_LEN_3 0x7 #define ARM_BREAKPOINT_LEN_4 0xf +#define ARM_BREAKPOINT_LEN_5 0x1f +#define ARM_BREAKPOINT_LEN_6 0x3f +#define ARM_BREAKPOINT_LEN_7 0x7f #define ARM_BREAKPOINT_LEN_8 0xff /* Kernel stepping */ @@ -107,7 +111,7 @@ struct perf_event; struct pmu; extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, - int *gen_len, int *gen_type); + int *gen_len, int *gen_type, int *offset); extern int arch_check_bp_in_kernelspace(struct perf_event *bp); extern int arch_validate_hwbkpt_settings(struct perf_event *bp); extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 547d4f9e96e0b609affb34a114f378a996db83c3..227ac1fa2e425ea5501e3ac50ef8480e75507e2c 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -41,4 +41,11 @@ static inline void arm64_pmu_unlock(raw_spinlock_t *lock, unsigned long *flags) { } #endif +#define perf_arch_fetch_caller_regs(regs, __ip) { \ + (regs)->pc = (__ip); \ + (regs)->regs[29] = (unsigned long) __builtin_frame_address(0); \ + (regs)->sp = current_stack_pointer; \ + (regs)->pstate = PSR_MODE_EL1h; \ +} + #endif diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h index de003327be97dfcb36532376d349f23c91d899d7..330412e1fb3d6948dd1b7a00037213e49c0f3f1a 100644 --- a/arch/arm64/include/asm/stackprotector.h +++ b/arch/arm64/include/asm/stackprotector.h @@ -31,6 +31,9 @@ static __always_inline void boot_init_stack_canary(void) get_random_bytes(&canary, sizeof(canary)); canary ^= LINUX_VERSION_CODE; + /* Sacrifice 8 bits of entropy to mitigate non-terminated C string overflows */ + canary &= ~(unsigned long)0xff; + current->stack_canary = canary; __stack_chk_guard = current->stack_canary; } diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index f4091da4d972af9b8408a330bac75077adebc186..c3216a60d3f3acab88adb68ef233b3b1c351fe46 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -68,6 +68,11 @@ struct thread_info { #define init_thread_info (init_thread_union.thread_info) #define init_stack (init_thread_union.stack) +/* + * how to get the current stack pointer from C + */ +register unsigned long current_stack_pointer asm ("sp"); + /* * how to get the thread information struct from C */ diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S index d358ccacfc00275bd8ef8462e8839ac9f12161f8..c44a82f146b16664850ddadbfdc4699784c4e468 100644 --- a/arch/arm64/kernel/entry-fpsimd.S +++ b/arch/arm64/kernel/entry-fpsimd.S @@ -52,7 +52,7 @@ ENDPROC(fpsimd_load_state) ENTRY(fpsimd_save_partial_state) fpsimd_save_partial x0, 1, 8, 9 ret -ENDPROC(fpsimd_load_partial_state) +ENDPROC(fpsimd_save_partial_state) /* * Load the bottom n FP registers. diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 17b99ae8dbd9868958ab474be1546f0d450f5e36..2a24662ef9d94e0e88fe2e0f719e950cc3712e10 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -378,7 +378,7 @@ el0_sync: cmp x24, #ESR_EL1_EC_FP_EXC64 // FP/ASIMD exception b.eq el0_fpsimd_exc cmp x24, #ESR_EL1_EC_SYS64 // configurable trap - b.eq el0_undef + b.eq el0_sys cmp x24, #ESR_EL1_EC_SP_ALIGN // stack alignment exception b.eq el0_sp_pc cmp x24, #ESR_EL1_EC_PC_ALIGN // pc alignment exception @@ -491,6 +491,15 @@ el0_undef: enable_dbg_and_irq mov x0, sp b do_undefinstr +el0_sys: + /* + * System instructions, for trapped cache maintenance instructions + */ + enable_dbg + enable_irq + mov x0, x25 + mov x1, sp + b do_sysinstr el0_dbg: /* * Debug exception handling @@ -642,12 +651,15 @@ ENDPROC(el0_svc) * switches, and waiting for our parent to respond. */ __sys_trace: - mov x0, sp + mov w0, #-1 // set default errno for + cmp scno, x0 // user-issued syscall(-1) + b.ne 1f + mov x0, #-ENOSYS + str x0, [sp, #S_X0] +1: mov x0, sp bl syscall_trace_enter adr lr, __sys_trace_return // return address - cmp w0, #RET_SKIP_SYSCALL_TRACE // skip syscall and tracing? - b.eq ret_to_user - cmp w0, #RET_SKIP_SYSCALL // skip syscall? + cmp w0, #-1 // skip the syscall? b.eq __sys_trace_return_skipped uxtw scno, w0 // syscall number (possibly new) mov x1, sp // pointer to regs @@ -661,8 +673,8 @@ __sys_trace: br x16 // call sys_* routine __sys_trace_return: - str x0, [sp] // save returned x0 -__sys_trace_return_skipped: // x0 already in regs[0] + str x0, [sp, #S_X0] // save returned x0 +__sys_trace_return_skipped: mov x0, sp bl syscall_trace_exit b ret_to_user diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index de7b854438d7902f9feef828e392955f69e4c988..7414d8a9a133e89599a58735bc9ed82892b294ab 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -311,9 +311,21 @@ static int get_hbp_len(u8 hbp_len) case ARM_BREAKPOINT_LEN_2: len_in_bytes = 2; break; + case ARM_BREAKPOINT_LEN_3: + len_in_bytes = 3; + break; case ARM_BREAKPOINT_LEN_4: len_in_bytes = 4; break; + case ARM_BREAKPOINT_LEN_5: + len_in_bytes = 5; + break; + case ARM_BREAKPOINT_LEN_6: + len_in_bytes = 6; + break; + case ARM_BREAKPOINT_LEN_7: + len_in_bytes = 7; + break; case ARM_BREAKPOINT_LEN_8: len_in_bytes = 8; break; @@ -343,7 +355,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp) * to generic breakpoint descriptions. */ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, - int *gen_len, int *gen_type) + int *gen_len, int *gen_type, int *offset) { /* Type */ switch (ctrl.type) { @@ -363,17 +375,33 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, return -EINVAL; } + if (!ctrl.len) + return -EINVAL; + *offset = __ffs(ctrl.len); + /* Len */ - switch (ctrl.len) { + switch (ctrl.len >> *offset) { case ARM_BREAKPOINT_LEN_1: *gen_len = HW_BREAKPOINT_LEN_1; break; case ARM_BREAKPOINT_LEN_2: *gen_len = HW_BREAKPOINT_LEN_2; break; + case ARM_BREAKPOINT_LEN_3: + *gen_len = HW_BREAKPOINT_LEN_3; + break; case ARM_BREAKPOINT_LEN_4: *gen_len = HW_BREAKPOINT_LEN_4; break; + case ARM_BREAKPOINT_LEN_5: + *gen_len = HW_BREAKPOINT_LEN_5; + break; + case ARM_BREAKPOINT_LEN_6: + *gen_len = HW_BREAKPOINT_LEN_6; + break; + case ARM_BREAKPOINT_LEN_7: + *gen_len = HW_BREAKPOINT_LEN_7; + break; case ARM_BREAKPOINT_LEN_8: *gen_len = HW_BREAKPOINT_LEN_8; break; @@ -417,9 +445,21 @@ static int arch_build_bp_info(struct perf_event *bp) case HW_BREAKPOINT_LEN_2: info->ctrl.len = ARM_BREAKPOINT_LEN_2; break; + case HW_BREAKPOINT_LEN_3: + info->ctrl.len = ARM_BREAKPOINT_LEN_3; + break; case HW_BREAKPOINT_LEN_4: info->ctrl.len = ARM_BREAKPOINT_LEN_4; break; + case HW_BREAKPOINT_LEN_5: + info->ctrl.len = ARM_BREAKPOINT_LEN_5; + break; + case HW_BREAKPOINT_LEN_6: + info->ctrl.len = ARM_BREAKPOINT_LEN_6; + break; + case HW_BREAKPOINT_LEN_7: + info->ctrl.len = ARM_BREAKPOINT_LEN_7; + break; case HW_BREAKPOINT_LEN_8: info->ctrl.len = ARM_BREAKPOINT_LEN_8; break; @@ -511,18 +551,17 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) default: return -EINVAL; } - - info->address &= ~alignment_mask; - info->ctrl.len <<= offset; } else { if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) alignment_mask = 0x3; else alignment_mask = 0x7; - if (info->address & alignment_mask) - return -EINVAL; + offset = info->address & alignment_mask; } + info->address &= ~alignment_mask; + info->ctrl.len <<= offset; + /* * Disallow per-task kernel breakpoints since these would * complicate the stepping code. @@ -657,8 +696,8 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr, struct pt_regs *regs) { int i, step = 0, *kernel_step, access; - u32 ctrl_reg; - u64 val, alignment_mask; + u32 ctrl_reg, lens, lene; + u64 val; struct perf_event *wp, **slots; struct debug_info *debug_info; struct arch_hw_breakpoint *info; @@ -676,25 +715,21 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr, goto unlock; info = counter_arch_bp(wp); - /* AArch32 watchpoints are either 4 or 8 bytes aligned. */ - if (is_compat_task()) { - if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) - alignment_mask = 0x7; - else - alignment_mask = 0x3; - } else { - alignment_mask = 0x7; - } - /* Check if the watchpoint value matches. */ + /* Check if the watchpoint value and byte select match. */ val = read_wb_reg(AARCH64_DBG_REG_WVR, i); - if (val != (addr & ~alignment_mask)) - goto unlock; - - /* Possible match, check the byte address select to confirm. */ ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i); decode_ctrl_reg(ctrl_reg, &ctrl); - if (!((1 << (addr & alignment_mask)) & ctrl.len)) + lens = ffs(ctrl.len) - 1; + lene = fls(ctrl.len) - 1; + /* + * FIXME: reported address can be anywhere between "the + * lowest address accessed by the memory access that + * triggered the watchpoint" and "the highest watchpointed + * address accessed by the memory access". So, it may not + * lie in the interval of watchpoint address range. + */ + if (addr < val + lens || addr > val + lene) goto unlock; /* diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index dbb52c0dad5b650ba24a52448c79b96dad18a88f..f7ae2943fe9271773ccc8c776d3b05ce9b20e838 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -224,13 +224,13 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, struct arch_hw_breakpoint_ctrl ctrl, struct perf_event_attr *attr) { - int err, len, type, disabled = !ctrl.enabled; + int err, len, type, offset, disabled = !ctrl.enabled; attr->disabled = disabled; if (disabled) return 0; - err = arch_bp_generic_fields(ctrl, &len, &type); + err = arch_bp_generic_fields(ctrl, &len, &type, &offset); if (err) return err; @@ -249,6 +249,7 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, attr->bp_len = len; attr->bp_type = type; + attr->bp_addr += offset; return 0; } @@ -301,7 +302,7 @@ static int ptrace_hbp_get_addr(unsigned int note_type, if (IS_ERR(bp)) return PTR_ERR(bp); - *addr = bp ? bp->attr.bp_addr : 0; + *addr = bp ? counter_arch_bp(bp)->address : 0; return 0; } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3ef5cff918cce9d369acc43656f350ebefb90678..493f55ae11da39f1cb8c872d5a101a1e1a4b5ebc 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -533,14 +533,20 @@ static const char *compat_hwcap_str[] = { "evtstrm", NULL }; -#endif /* CONFIG_COMPAT */ +static const char *compat_hwcap2_str[] = { + "aes", + "pmull", + "sha1", + "sha2", + "crc32", + NULL +}; +#endif /* CONFIG_COMPAT */ static int c_show(struct seq_file *m, void *v) { int i, j; - seq_printf(m, "Processor\t: %s rev %d (%s)\n", - cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); for_each_present_cpu(i) { struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); u32 midr = cpuinfo->reg_midr; @@ -561,17 +567,22 @@ static int c_show(struct seq_file *m, void *v) * software which does already (at least for 32-bit). */ seq_puts(m, "Features\t:"); + if (personality(current->personality) == PER_LINUX32) { #ifdef CONFIG_COMPAT for (j = 0; compat_hwcap_str[j]; j++) if (COMPAT_ELF_HWCAP & (1 << j)) seq_printf(m, " %s", compat_hwcap_str[j]); + + for (j = 0; compat_hwcap2_str[j]; j++) + if (compat_elf_hwcap2 & (1 << j)) + seq_printf(m, " %s", compat_hwcap2_str[j]); #endif /* CONFIG_COMPAT */ } else { for (j = 0; hwcap_str[j]; j++) if (elf_hwcap & (1 << j)) seq_printf(m, " %s", hwcap_str[j]); - } + } seq_puts(m, "\n"); seq_printf(m, "CPU implementer\t: 0x%02x\n", (midr >> 24)); @@ -580,13 +591,6 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "CPU part\t: 0x%03x\n", ((midr >> 4) & 0xfff)); seq_printf(m, "CPU revision\t: %d\n\n", (midr & 0xf)); } -#ifdef CONFIG_ARMV7_COMPAT_CPUINFO - if (is_compat_task()) { - /* Print out the non-optional ARMv8 HW capabilities */ - seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi "); - seq_printf(m, "vfpv4 idiva idivt "); - } -#endif if (!arch_read_hardware_id) seq_printf(m, "Hardware\t: %s\n", machine_name); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 73ad727ccd566f92506d08781ef9e793f1ba6818..4d41b187ca85b77ceae5739d4227d7c3ea13eebc 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -158,6 +158,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) if (cpu_ops[cpu]->cpu_postboot) cpu_ops[cpu]->cpu_postboot(); + /* + * Log the CPU info before it is marked online and might get read. + */ + cpuinfo_store_cpu(); + /* * Enable GIC and timers. */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 54122c4fd19a8f6907f939a2fabec97e613840a9..55437ba1f5a4901984e368dca7c43d5c76c218b3 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -48,7 +48,11 @@ int notrace unwind_frame(struct stackframe *frame) frame->sp = fp + 0x10; frame->fp = *(unsigned long *)(fp); - frame->pc = *(unsigned long *)(fp + 8); + /* + * -4 here because we care about the PC at time of bl, + * not where the return will go. + */ + frame->pc = *(unsigned long *)(fp + 8) - 4; return 0; } diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 0e1447cbadd741972fdcd6abc1eaf93bd9a5b590..85c176cf92b4b2c64b1ea8259edf83a03b1a7c4d 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -32,8 +32,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -381,6 +383,25 @@ die_sig: arm64_notify_die("Oops - undefined instruction", regs, &info, 0); } +static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs) +{ + int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; + + if (rt != 31) + regs->regs[rt] = arch_counter_get_cntvct(); + regs->pc += 4; +} + +asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs) +{ + if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTVCT) { + cntvct_read_handler(esr, regs); + return; + } + + do_undefinstr(regs); +} + long compat_arm_syscall(struct pt_regs *regs); asmlinkage long do_ni_syscall(struct pt_regs *regs) diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index c67ab2c60dc6776a78151e63d76bc748dc3162c3..d3cfc2df5de3e3c9c3f5ab2dce286a29caf5e910 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -59,9 +59,6 @@ static unsigned long mmap_rnd(void) #endif rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); } - if (current->flags & PF_RANDOMIZE) - rnd = (long)get_random_int() & STACK_RND_MASK; - return rnd << PAGE_SHIFT; } diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c index bed9a9bd3c10c84e004c845839f0ad53c0565e45..785344bbdc07c360e81768c8472336bebd0baa3e 100644 --- a/arch/frv/mm/highmem.c +++ b/arch/frv/mm/highmem.c @@ -42,6 +42,7 @@ void *kmap_atomic(struct page *page) unsigned long paddr; int type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); paddr = page_to_phys(page); @@ -85,5 +86,6 @@ void __kunmap_atomic(void *kvaddr) } kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/metag/mm/highmem.c b/arch/metag/mm/highmem.c index d71f621a2c0b92adb5679162d1cd59568440986b..807f1b1c4e6567738f676c935ad21483e4972a32 100644 --- a/arch/metag/mm/highmem.c +++ b/arch/metag/mm/highmem.c @@ -43,7 +43,7 @@ void *kmap_atomic(struct page *page) unsigned long vaddr; int type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -82,6 +82,7 @@ void __kunmap_atomic(void *kvaddr) } pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); @@ -95,6 +96,7 @@ void *kmap_atomic_pfn(unsigned long pfn) unsigned long vaddr; int type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h index d0463893243888f47bf1e740d7ebf0e68fb087c4..0936682a3bd40068d5d18f7cfd23d1efaab74a4a 100644 --- a/arch/microblaze/include/asm/highmem.h +++ b/arch/microblaze/include/asm/highmem.h @@ -50,30 +50,19 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_high(struct page *page); -extern void kunmap_high(struct page *page); -extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); -extern void __kunmap_atomic(void *kvaddr); - -static inline void *kmap(struct page *page) +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) { - might_sleep(); + preempt_disable(); + pagefault_disable(); if (!PageHighMem(page)) return page_address(page); - return kmap_high(page); -} -static inline void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); + return kmap_atomic_high_prot(page, prot); } -static inline void *kmap_atomic(struct page *page) +static inline void *kmap_atomic_high(struct page *page) { - return kmap_atomic_prot(page, kmap_prot); + return kmap_atomic_high_prot(page, kmap_prot); } static inline struct page *kmap_atomic_to_page(void *ptr) diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c index 5a92576fad927127eb05fbe24833b57e18ba7155..a05686b7eedfad98ba911f4d24fa68e74608df03 100644 --- a/arch/microblaze/mm/highmem.c +++ b/arch/microblaze/mm/highmem.c @@ -37,7 +37,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -56,15 +56,13 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type; - if (vaddr < __fix_to_virt(FIX_KMAP_END)) { - pagefault_enable(); + if (vaddr < __fix_to_virt(FIX_KMAP_END)) return; - } type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM @@ -83,6 +81,5 @@ void __kunmap_atomic(void *kvaddr) } #endif kmap_atomic_idx_pop(); - pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index b0dd0c84df7040dadb1f8d82f5f8b849d2c5a5a4..9c5b703f43136efe099c2dada0a8b28861b3fe1f 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -42,13 +42,8 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void * kmap_high(struct page *page); -extern void kunmap_high(struct page *page); - -extern void *kmap(struct page *page); -extern void kunmap(struct page *page); -extern void *kmap_atomic(struct page *page); -extern void __kunmap_atomic(void *kvaddr); +#define ARCH_HAS_KMAP_FLUSH_TLB +extern void kmap_flush_tlb(unsigned long addr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(void *ptr); @@ -56,8 +51,6 @@ extern struct page *kmap_atomic_to_page(void *ptr); extern void kmap_init(void); -#define kmap_prot PAGE_KERNEL - #endif /* __KERNEL__ */ #endif /* _ASM_HIGHMEM_H */ diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 5aeb3eb0b72f87b5f108a6d287517e53d038be2a..44fb5f5946799c2af94a14be2df12ffd38f19468 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,9 @@ void __flush_dcache_page(struct page *page) */ addr = (unsigned long) page_address(page); flush_data_cache_page(addr); + + if (PageHighMem(page)) + kunmap_atomic((void *)addr); } EXPORT_SYMBOL(__flush_dcache_page); @@ -134,6 +138,10 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address, addr = (unsigned long) page_address(page); if (exec || pages_do_alias(addr, address & PAGE_MASK)) flush_data_cache_page(addr); + + if (PageHighMem(page)) + kunmap_atomic((void *)addr); + ClearPageDcacheDirty(page); } } diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index da815d295239baaaf6e1d1069e2255baa8d75358..fbb9df0c1c2fdb03fb1e9cd6775d7e13da776b65 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -10,70 +10,37 @@ static pte_t *kmap_pte; unsigned long highstart_pfn, highend_pfn; -void *kmap(struct page *page) +void kmap_flush_tlb(unsigned long addr) { - void *addr; - - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - addr = kmap_high(page); - flush_tlb_one((unsigned long)addr); - - return addr; + flush_tlb_one(addr); } -EXPORT_SYMBOL(kmap); +EXPORT_SYMBOL(kmap_flush_tlb); -void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); - -/* - * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because - * no global lock is needed and because the kmap code must perform a global TLB - * invalidation when the kmap pool wraps. - * - * However when holding an atomic kmap is is not legal to sleep, so atomic - * kmaps are appropriate for short, tight code paths only. - */ - -void *kmap_atomic(struct page *page) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); #ifdef CONFIG_DEBUG_HIGHMEM BUG_ON(!pte_none(*(kmap_pte - idx))); #endif - set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); + set_pte(kmap_pte-idx, mk_pte(page, prot)); local_flush_tlb_one((unsigned long)vaddr); return (void*) vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type __maybe_unused; - if (vaddr < FIXADDR_START) { // FIXME - pagefault_enable(); + if (vaddr < FIXADDR_START) return; - } type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM @@ -91,9 +58,8 @@ void __kunmap_atomic(void *kvaddr) } #endif kmap_atomic_idx_pop(); - pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); /* * This is the same as kmap_atomic() but can map memory that doesn't @@ -104,6 +70,7 @@ void *kmap_atomic_pfn(unsigned long pfn) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h index 7c137cd8aa37490e07e2e9b7e917785e63236f5b..4f03a3ea0f6a6fc00a59b447712a9b5ca4503c00 100644 --- a/arch/mn10300/include/asm/highmem.h +++ b/arch/mn10300/include/asm/highmem.h @@ -75,6 +75,7 @@ static inline unsigned long kmap_atomic(struct page *page) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); if (page < highmem_start_page) return page_address(page); @@ -98,6 +99,7 @@ static inline void __kunmap_atomic(unsigned long vaddr) if (vaddr < FIXADDR_START) { /* FIXME */ pagefault_enable(); + preempt_enable(); return; } @@ -122,6 +124,7 @@ static inline void __kunmap_atomic(unsigned long vaddr) kmap_atomic_idx_pop(); pagefault_enable(); + preempt_enable(); } #endif /* __KERNEL__ */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index de65f66ea64e7538f4f7c431ca3800e86c152e5d..8431c133f6eae76665e8da74cbac95df32216054 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -142,14 +142,14 @@ static inline void kunmap(struct page *page) static inline void *kmap_atomic(struct page *page) { + preempt_disable(); pagefault_disable(); return page_address(page); } -static inline void __kunmap_atomic(void *addr) +static inline void kunmap_atomic_high(void *addr) { flush_kernel_dcache_page_addr(addr); - pagefault_enable(); } #define kmap_atomic_prot(page, prot) kmap_atomic(page) diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index caaf6e00630d0d74b2966b1bce89a367ad3ceaa6..d466cc49368f01b56ce8fe2a2e770679264d6d8a 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -58,30 +58,19 @@ extern pte_t *pkmap_page_table; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_high(struct page *page); -extern void kunmap_high(struct page *page); -extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); -extern void __kunmap_atomic(void *kvaddr); - -static inline void *kmap(struct page *page) +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) { - might_sleep(); + preempt_disable(); + pagefault_disable(); if (!PageHighMem(page)) return page_address(page); - return kmap_high(page); -} -static inline void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); + return kmap_atomic_high_prot(page, prot); } -static inline void *kmap_atomic(struct page *page) +static inline void *kmap_atomic_high(struct page *page) { - return kmap_atomic_prot(page, kmap_prot); + return kmap_atomic_high_prot(page, kmap_prot); } static inline struct page *kmap_atomic_to_page(void *ptr) diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c index e7450bdbe83a9380264fc149c4831b587226cd36..861b6ccfe74872bbc7aaa985560c5f569feb5f27 100644 --- a/arch/powerpc/mm/highmem.c +++ b/arch/powerpc/mm/highmem.c @@ -23,18 +23,12 @@ #include #include -/* - * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap - * gives a more generic (and caching) interface. But kmap_atomic can - * be used in IRQ contexts, so in some (very limited) cases we need - * it. - */ -void *kmap_atomic_prot(struct page *page, pgprot_t prot) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -52,15 +46,13 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type; - if (vaddr < __fix_to_virt(FIX_KMAP_END)) { - pagefault_enable(); + if (vaddr < __fix_to_virt(FIX_KMAP_END)) return; - } type = kmap_atomic_idx(); @@ -81,6 +73,5 @@ void __kunmap_atomic(void *kvaddr) #endif kmap_atomic_idx_pop(); - pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 4f9e15c757e2f40ac9e4706afa6f31c03131b434..ea39323a0f3382bcf5701b5cdeda83db3afa0731 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -24,11 +24,12 @@ #include #include #include +#include /* declarations for highmem.c */ extern unsigned long highstart_pfn, highend_pfn; -extern pgprot_t kmap_prot; +#define kmap_prot __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE) extern pte_t *pkmap_page_table; extern void kmap_init(void) __init; @@ -49,28 +50,6 @@ extern void kmap_init(void) __init; #define PKMAP_END (PKMAP_ADDR(LAST_PKMAP)) -extern void *kmap_high(struct page *page); -extern void kunmap_high(struct page *page); - -static inline void *kmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} - -static inline void kunmap(struct page *page) -{ - BUG_ON(in_interrupt()); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} - -extern void *kmap_atomic(struct page *page); -extern void __kunmap_atomic(void *kvaddr); - #define flush_cache_kmaps() flush_cache_all() #endif /* __KERNEL__ */ diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 449f864f0cefdb8918bf0002d40dc87ba2cb8db3..22388690924543913b00f72337011b99a827fd07 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -31,8 +31,6 @@ #include #include -pgprot_t kmap_prot; - static pte_t *kmap_pte; void __init kmap_init(void) @@ -45,19 +43,13 @@ void __init kmap_init(void) /* cache the first kmap pte */ kmap_pte = pte_offset_kernel(dir, address); - kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE); } -void *kmap_atomic(struct page *page) +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; long idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ - pagefault_disable(); - if (!PageHighMem(page)) - return page_address(page); - type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); @@ -72,7 +64,7 @@ void *kmap_atomic(struct page *page) #ifdef CONFIG_DEBUG_HIGHMEM BUG_ON(!pte_none(*(kmap_pte-idx))); #endif - set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); + set_pte(kmap_pte-idx, mk_pte(page, prot)); /* XXX Fix - Anton */ #if 0 __flush_tlb_one(vaddr); @@ -82,17 +74,15 @@ void *kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kmap_atomic_high_prot); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; int type; - if (vaddr < FIXADDR_START) { // FIXME - pagefault_enable(); + if (vaddr < FIXADDR_START) return; - } type = kmap_atomic_idx(); @@ -125,6 +115,5 @@ void __kunmap_atomic(void *kvaddr) #endif kmap_atomic_idx_pop(); - pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 347d123b14be961785fb2031727371c18b95723a..2807600c4b6bad6cb651d9bd47f827394d33946a 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c @@ -202,7 +202,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) int idx, type; pte_t *pte; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); /* Avoid icache flushes by disallowing atomic executable mappings. */ @@ -261,6 +261,7 @@ void __kunmap_atomic(void *kvaddr) arch_flush_lazy_mmu_mode(); pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 9d7d36c82fc21aa7d640e613ffa87d7a48a3034e..41d69dd35ced38f0280abd7f514187f44ef7db47 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -160,7 +160,6 @@ extern void reserve_top_address(unsigned long reserve); extern int fixmaps_set; extern pte_t *kmap_pte; -extern pgprot_t kmap_prot; extern pte_t *pkmap_page_table; void __native_set_fixmap(enum fixed_addresses idx, pte_t pte); diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index 302a323b3f671065b34f09766fb58b344fe78fe3..ce4a2294a9b527c82644e889045e603e682339f7 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -54,15 +54,6 @@ extern unsigned long highstart_pfn, highend_pfn; #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern void *kmap_high(struct page *page); -extern void kunmap_high(struct page *page); - -void *kmap(struct page *page); -void kunmap(struct page *page); - -void *kmap_atomic_prot(struct page *page, pgprot_t prot); -void *kmap_atomic(struct page *page); -void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/x86/include/asm/refcount.h b/arch/x86/include/asm/refcount.h new file mode 100644 index 0000000000000000000000000000000000000000..6b5b479096abc94c89d35bd382d5decea9626f1e --- /dev/null +++ b/arch/x86/include/asm/refcount.h @@ -0,0 +1,136 @@ +#ifndef __ASM_X86_REFCOUNT_H +#define __ASM_X86_REFCOUNT_H +/* + * x86-specific implementation of refcount_t. Based on PAX_REFCOUNT from + * PaX/grsecurity. + */ +#include +#include + +/* + * This is the first portion of the refcount error handling, which lives in + * .text.unlikely, and is jumped to from the CPU flag check (in the + * following macros). This saves the refcount value location into CX for + * the exception handler to use (in mm/extable.c), and then triggers the + * central refcount exception. The fixup address for the exception points + * back to the regular execution flow in .text. + */ +#define _REFCOUNT_EXCEPTION \ + ".pushsection .text..refcount\n" \ + "111:\tlea %[counter], %%" _ASM_CX "\n" \ + "112:\t" ASM_UD2 "\n" \ + ASM_UNREACHABLE \ + ".popsection\n" \ + "113:\n" \ + _ASM_EXTABLE_REFCOUNT(112b, 113b) + +/* Trigger refcount exception if refcount result is negative. */ +#define REFCOUNT_CHECK_LT_ZERO \ + "js 111f\n\t" \ + _REFCOUNT_EXCEPTION + +/* Trigger refcount exception if refcount result is zero or negative. */ +#define REFCOUNT_CHECK_LE_ZERO \ + "jz 111f\n\t" \ + REFCOUNT_CHECK_LT_ZERO + +/* Trigger refcount exception unconditionally. */ +#define REFCOUNT_ERROR \ + "jmp 111f\n\t" \ + _REFCOUNT_EXCEPTION + +static __always_inline void refcount_add(unsigned int i, refcount_t *r) +{ + asm volatile(LOCK_PREFIX "addl %1,%0\n\t" + REFCOUNT_CHECK_LT_ZERO + : [counter] "+m" (r->refs.counter) + : "ir" (i) + : "cc", "cx"); +} + +static __always_inline void refcount_inc(refcount_t *r) +{ + asm volatile(LOCK_PREFIX "incl %0\n\t" + REFCOUNT_CHECK_LT_ZERO + : [counter] "+m" (r->refs.counter) + : : "cc", "cx"); +} + +static __always_inline void refcount_dec(refcount_t *r) +{ + asm volatile(LOCK_PREFIX "decl %0\n\t" + REFCOUNT_CHECK_LE_ZERO + : [counter] "+m" (r->refs.counter) + : : "cc", "cx"); +} + +static __always_inline __must_check +bool refcount_sub_and_test(unsigned int i, refcount_t *r) +{ +<<<<<<< HEAD + GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, "er", i, "%0", e, "cx"); +======= + bool ret = GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", + REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, e, "er", i, "cx"); + + if (ret) { + smp_acquire__after_ctrl_dep(); + return true; + } + + return false; +>>>>>>> 47b8f3ab9c49 (refcount_t: Add ACQUIRE ordering on success for dec(sub)_and_test() variants) +} + +static __always_inline __must_check bool refcount_dec_and_test(refcount_t *r) +{ +<<<<<<< HEAD + GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl", REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, "%0", e, "cx"); +======= + bool ret = GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl", + REFCOUNT_CHECK_LT_ZERO, + r->refs.counter, e, "cx"); + + if (ret) { + smp_acquire__after_ctrl_dep(); + return true; + } + + return false; +>>>>>>> 47b8f3ab9c49 (refcount_t: Add ACQUIRE ordering on success for dec(sub)_and_test() variants) +} + +static __always_inline __must_check +bool refcount_add_not_zero(unsigned int i, refcount_t *r) +{ + int c, result; + + c = atomic_read(&(r->refs)); + do { + if (unlikely(c == 0)) + return false; + + result = c + i; + + /* Did we try to increment from/to an undesirable state? */ + if (unlikely(c < 0 || c == INT_MAX || result < c)) { + asm volatile(REFCOUNT_ERROR + : : [counter] "m" (r->refs.counter) + : "cc", "cx"); + break; + } + + } while (!atomic_try_cmpxchg(&(r->refs), &c, result)); + + return c != 0; +} + +static __always_inline __must_check bool refcount_inc_not_zero(refcount_t *r) +{ + return refcount_add_not_zero(1, r); +} + +#endif diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 4500142bc4aa46429cb2be41a7ee3407426f6155..334a69c1f00d2c5ca604e75dbb89a790f411147a 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -3,24 +3,6 @@ #include /* for totalram_pages */ #include -void *kmap(struct page *page) -{ - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - return kmap_high(page); -} -EXPORT_SYMBOL(kmap); - -void kunmap(struct page *page) -{ - if (in_interrupt()) - BUG(); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); /* * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because @@ -35,7 +17,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) unsigned long vaddr; int idx, type; - /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + preempt_disable(); pagefault_disable(); if (!PageHighMem(page)) @@ -52,12 +34,6 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void *kmap_atomic(struct page *page) -{ - return kmap_atomic_prot(page, kmap_prot); -} -EXPORT_SYMBOL(kmap_atomic); - /* * This is the same as kmap_atomic() but can map memory that doesn't * have a struct page associated with it. @@ -68,7 +44,7 @@ void *kmap_atomic_pfn(unsigned long pfn) } EXPORT_SYMBOL_GPL(kmap_atomic_pfn); -void __kunmap_atomic(void *kvaddr) +void kunmap_atomic_high(void *kvaddr) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; @@ -98,10 +74,8 @@ void __kunmap_atomic(void *kvaddr) BUG_ON(vaddr >= (unsigned long)high_memory); } #endif - - pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_high); struct page *kmap_atomic_to_page(void *ptr) { diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c index 7b179b499fa30944adfbacf0b19a1e042fd4ebe8..89f860138b61b786b9d999ac481bda4a7289e0ca 100644 --- a/arch/x86/mm/iomap_32.c +++ b/arch/x86/mm/iomap_32.c @@ -59,6 +59,7 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot) unsigned long vaddr; int idx, type; + preempt_disable(); pagefault_disable(); type = kmap_atomic_idx_push(); @@ -115,5 +116,6 @@ iounmap_atomic(void __iomem *kvaddr) } pagefault_enable(); + preempt_enable(); } EXPORT_SYMBOL_GPL(iounmap_atomic); diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h index 80be15124697d8e85a23859a466e97f178936010..241fee8bdb067eb3482609df444b4d84281c0c5f 100644 --- a/arch/xtensa/include/asm/highmem.h +++ b/arch/xtensa/include/asm/highmem.h @@ -11,6 +11,62 @@ #ifndef _XTENSA_HIGHMEM_H #define _XTENSA_HIGHMEM_H -extern void flush_cache_kmaps(void); +#include +#include +#include +#include +#include + +#define PKMAP_BASE ((FIXADDR_START - \ + (LAST_PKMAP + 1) * PAGE_SIZE) & PMD_MASK) +#define LAST_PKMAP (PTRS_PER_PTE * DCACHE_N_COLORS) +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define kmap_prot PAGE_KERNEL_EXEC + +#if DCACHE_WAY_SIZE > PAGE_SIZE +#define get_pkmap_color get_pkmap_color +static inline int get_pkmap_color(struct page *page) +{ + return DCACHE_ALIAS(page_to_phys(page)); +} + +extern unsigned int last_pkmap_nr_arr[]; + +static inline unsigned int get_next_pkmap_nr(unsigned int color) +{ + last_pkmap_nr_arr[color] = + (last_pkmap_nr_arr[color] + DCACHE_N_COLORS) & LAST_PKMAP_MASK; + return last_pkmap_nr_arr[color] + color; +} + +static inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color) +{ + return pkmap_nr < DCACHE_N_COLORS; +} + +static inline int get_pkmap_entries_count(unsigned int color) +{ + return LAST_PKMAP / DCACHE_N_COLORS; +} + +extern wait_queue_head_t pkmap_map_wait_arr[]; + +static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) +{ + return pkmap_map_wait_arr + color; +} +#endif + +extern pte_t *pkmap_page_table; + +static inline void flush_cache_kmaps(void) +{ + flush_cache_all(); +} + +void kmap_init(void); #endif diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c new file mode 100644 index 0000000000000000000000000000000000000000..e9145f0a9adbb35f9109c1aee2efef0b811e6953 --- /dev/null +++ b/arch/xtensa/mm/highmem.c @@ -0,0 +1,87 @@ +/* + * High memory support for Xtensa architecture + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2014 Cadence Design Systems Inc. + */ + +#include +#include +#include + +static pte_t *kmap_pte; + +#if DCACHE_WAY_SIZE > PAGE_SIZE +unsigned int last_pkmap_nr_arr[DCACHE_N_COLORS]; +wait_queue_head_t pkmap_map_wait_arr[DCACHE_N_COLORS]; + +static void __init kmap_waitqueues_init(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pkmap_map_wait_arr); ++i) + init_waitqueue_head(pkmap_map_wait_arr + i); +} +#else +static inline void kmap_waitqueues_init(void) +{ +} +#endif + +static inline enum fixed_addresses kmap_idx(int type, unsigned long color) +{ + return (type + KM_TYPE_NR * smp_processor_id()) * DCACHE_N_COLORS + + color; +} + +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = kmap_idx(kmap_atomic_idx_push(), + DCACHE_ALIAS(page_to_phys(page))); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#ifdef CONFIG_DEBUG_HIGHMEM + BUG_ON(!pte_none(*(kmap_pte + idx))); +#endif + set_pte(kmap_pte + idx, mk_pte(page, prot)); + + return (void *)vaddr; +} +EXPORT_SYMBOL(kmap_atomic_high_prot); + +void kunmap_atomic_high(void *kvaddr) +{ + if (kvaddr >= (void *)FIXADDR_START && + kvaddr < (void *)FIXADDR_TOP) { + int idx = kmap_idx(kmap_atomic_idx(), + DCACHE_ALIAS((unsigned long)kvaddr)); + + /* + * Force other mappings to Oops if they'll try to access this + * pte without first remap it. Keeping stale mappings around + * is a bad idea also, in case the page changes cacheability + * attributes or becomes a protected page in a hypervisor. + */ + pte_clear(&init_mm, kvaddr, kmap_pte + idx); + local_flush_tlb_kernel_range((unsigned long)kvaddr, + (unsigned long)kvaddr + PAGE_SIZE); + + kmap_atomic_idx_pop(); + } +} +EXPORT_SYMBOL(kunmap_atomic_high); + +void __init kmap_init(void) +{ + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); + kmap_waitqueues_init(); +} diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 4d4cdc1a6e257c2df4aab9ca0ec9126cb6969415..de8dc280e751390a0a2bc0aa662d65f6e3f7a20c 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -1,5 +1,5 @@ menu "Android" - + config ANDROID bool "Android Drivers" ---help--- @@ -9,7 +9,7 @@ if ANDROID config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" - depends on MMU + depends on MMU && !M68K default n ---help--- Binder is used in Android for both communication between processes, @@ -19,6 +19,18 @@ config ANDROID_BINDER_IPC Android process, using Binder to identify, invoke and pass arguments between said processes. +config ANDROID_BINDERFS + bool "Android Binderfs filesystem" + depends on ANDROID_BINDER_IPC + default n + ---help--- + Binderfs is a pseudo-filesystem for the Android Binder IPC driver + which can be mounted per-ipc namespace allowing to run multiple + instances of Android. + Each binderfs mount initially only contains a binder-control device. + It can be used to dynamically allocate new binder IPC devices via + ioctls. + config ANDROID_BINDER_DEVICES string "Android Binder devices" depends on ANDROID_BINDER_IPC @@ -31,18 +43,15 @@ config ANDROID_BINDER_DEVICES created. Each binder device has its own context manager, and is therefore logically separated from the other devices. -config ANDROID_BINDER_IPC_32BIT - bool - depends on !64BIT && ANDROID_BINDER_IPC - default y - ---help--- - The Binder API has been changed to support both 32 and 64bit - applications in a mixed environment. - - Enable this to support an old 32-bit Android user-space (v4.4 and - earlier). +config ANDROID_BINDER_IPC_SELFTEST + bool "Android Binder IPC Driver Selftest" + depends on ANDROID_BINDER_IPC + ---help--- + This feature allows binder selftest to run. - Note that enabling this will break newer Android user-space. + Binder selftest checks the allocation and free of binder buffers + exhaustively with combinations of various buffer sizes and + alignments. endif # if ANDROID diff --git a/drivers/android/Makefile b/drivers/android/Makefile index 3b7e4b072c58c77dcd1b283711dfa96e34abdaa7..3432ab70b2098c79cb350b183690f20025e48a4b 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -1,3 +1,4 @@ ccflags-y += -I$(src) # needed for trace events - -obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o +obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o +obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5eb31c760d2816e0435c89fa66dfddd20c245855..6eafdb6f1a69e2eb5cee138da93e3840cf60ddcc 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1,4 +1,4 @@ -/* binder.c + /* binder.c * * Android IPC Subsystem * @@ -15,6 +15,40 @@ * */ +/* + * Locking overview + * + * There are 3 main spinlocks which must be acquired in the + * order shown: + * + * 1) proc->outer_lock : protects binder_ref + * binder_proc_lock() and binder_proc_unlock() are + * used to acq/rel. + * 2) node->lock : protects most fields of binder_node. + * binder_node_lock() and binder_node_unlock() are + * used to acq/rel + * 3) proc->inner_lock : protects the thread and node lists + * (proc->threads, proc->waiting_threads, proc->nodes) + * and all todo lists associated with the binder_proc + * (proc->todo, thread->todo, proc->delivered_death and + * node->async_todo), as well as thread->transaction_stack + * binder_inner_proc_lock() and binder_inner_proc_unlock() + * are used to acq/rel + * + * Any lock under procA must never be nested under any lock at the same + * level or below on procB. + * + * Functions that require a lock held on entry indicate which lock + * in the suffix of the function name: + * + * foo_olocked() : requires node->outer_lock + * foo_nlocked() : requires node->lock + * foo_ilocked() : requires proc->inner_lock + * foo_oilocked(): requires proc->outer_lock and proc->inner_lock + * foo_nilocked(): requires node->lock and proc->inner_lock + * ... + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -25,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -33,58 +66,50 @@ #include #include #include +#include #include #include -#include -#include #include #include +#include +#include +#include -#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT -#define BINDER_IPC_32BIT 1 -#endif - -#include +#include "binder.h" +#include "binder_alloc.h" +#include "binder_internal.h" #include "binder_trace.h" -#define BINDER_MIN_ALLOC (1 * PAGE_SIZE) +static HLIST_HEAD(binder_deferred_list); +static DEFINE_MUTEX(binder_deferred_lock); static HLIST_HEAD(binder_devices); +static HLIST_HEAD(binder_procs); +static DEFINE_MUTEX(binder_procs_lock); + +static HLIST_HEAD(binder_dead_nodes); +static DEFINE_SPINLOCK(binder_dead_nodes_lock); static struct dentry *binder_debugfs_dir_entry_root; static struct dentry *binder_debugfs_dir_entry_proc; -atomic_t binder_last_id; - -#define BINDER_DEBUG_ENTRY(name) \ -static int binder_##name##_open(struct inode *inode, struct file *file) \ -{ \ - return single_open(file, binder_##name##_show, inode->i_private); \ -} \ -\ -static const struct file_operations binder_##name##_fops = { \ - .owner = THIS_MODULE, \ - .open = binder_##name##_open, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ -} +static atomic_t binder_last_id; +static struct workqueue_struct *binder_deferred_workqueue; -static int binder_proc_show(struct seq_file *m, void *unused); -BINDER_DEBUG_ENTRY(proc); +static int proc_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(proc); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K #define SZ_1K 0x400 #endif -#ifndef SZ_4M -#define SZ_4M 0x400000 -#endif - #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) #define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) +#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) +#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) + enum { BINDER_DEBUG_USER_ERROR = 1U << 0, BINDER_DEBUG_FAILED_TRANSACTION = 1U << 1, @@ -99,19 +124,15 @@ enum { BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, BINDER_DEBUG_FREE_BUFFER = 1U << 11, BINDER_DEBUG_INTERNAL_REFS = 1U << 12, - BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, - BINDER_DEBUG_PRIORITY_CAP = 1U << 14, - BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, + BINDER_DEBUG_PRIORITY_CAP = 1U << 13, + BINDER_DEBUG_SPINLOCKS = 1U << 14, }; -static uint32_t binder_debug_mask; - -module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); - -static bool binder_debug_no_lock; -module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); +static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | + BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; +module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; -module_param_named(devices, binder_devices_param, charp, S_IRUGO); +module_param_named(devices, binder_devices_param, charp, 0444); static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); static int binder_stop_on_user_error; @@ -127,18 +148,18 @@ static int binder_set_stop_on_user_error(const char *val, return ret; } module_param_call(stop_on_user_error, binder_set_stop_on_user_error, - param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); + param_get_int, &binder_stop_on_user_error, 0644); #define binder_debug(mask, x...) \ do { \ if (binder_debug_mask & mask) \ - pr_info(x); \ + pr_info_ratelimited(x); \ } while (0) #define binder_user_error(x...) \ do { \ if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) \ - pr_info(x); \ + pr_info_ratelimited(x); \ if (binder_stop_on_user_error) \ binder_stop_on_user_error = 2; \ } while (0) @@ -166,94 +187,62 @@ enum binder_stat_types { }; struct binder_stats { - int br[_IOC_NR(BR_FAILED_REPLY) + 1]; - int bc[_IOC_NR(BC_REPLY_SG) + 1]; -}; - -/* These are still global, since it's not always easy to get the context */ -struct binder_obj_stats { + atomic_t br[_IOC_NR(BR_FROZEN_REPLY) + 1]; + atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; }; -static struct binder_obj_stats binder_obj_stats; +static struct binder_stats binder_stats; static inline void binder_stats_deleted(enum binder_stat_types type) { - atomic_inc(&binder_obj_stats.obj_deleted[type]); + atomic_inc(&binder_stats.obj_deleted[type]); } static inline void binder_stats_created(enum binder_stat_types type) { - atomic_inc(&binder_obj_stats.obj_created[type]); + atomic_inc(&binder_stats.obj_created[type]); } -struct binder_transaction_log_entry { - int debug_id; - int call_type; - int from_proc; - int from_thread; - int target_handle; - int to_proc; - int to_thread; - int to_node; - int data_size; - int offsets_size; - const char *context_name; -}; -struct binder_transaction_log { - int next; - int full; - struct binder_transaction_log_entry entry[32]; -}; +struct binder_transaction_log binder_transaction_log; +struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) { struct binder_transaction_log_entry *e; + unsigned int cur = atomic_inc_return(&log->cur); - e = &log->entry[log->next]; + if (cur >= ARRAY_SIZE(log->entry)) + log->full = true; + e = &log->entry[cur % ARRAY_SIZE(log->entry)]; + WRITE_ONCE(e->debug_id_done, 0); + /* + * write-barrier to synchronize access to e->debug_id_done. + * We make sure the initialized 0 value is seen before + * memset() other fields are zeroed by memset. + */ + smp_wmb(); memset(e, 0, sizeof(*e)); - log->next++; - if (log->next == ARRAY_SIZE(log->entry)) { - log->next = 0; - log->full = 1; - } return e; } -struct binder_context { - struct binder_node *binder_context_mgr_node; - kuid_t binder_context_mgr_uid; - const char *name; - - struct mutex binder_main_lock; - struct mutex binder_deferred_lock; - struct mutex binder_mmap_lock; - - struct hlist_head binder_procs; - struct hlist_head binder_dead_nodes; - struct hlist_head binder_deferred_list; - - struct work_struct deferred_work; - struct workqueue_struct *binder_deferred_workqueue; - struct binder_transaction_log transaction_log; - struct binder_transaction_log transaction_log_failed; - - struct binder_stats binder_stats; -}; - -struct binder_device { - struct hlist_node hlist; - struct miscdevice miscdev; - struct binder_context context; -}; +/** + * struct binder_work - work enqueued on a worklist + * @entry: node enqueued on list + * @type: type of work to be performed + * + * There are separate work lists for proc, thread, and node (async). + */ struct binder_work { struct list_head entry; - enum { + + enum binder_work_type { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_RETURN_ERROR, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, @@ -261,8 +250,77 @@ struct binder_work { } type; }; +struct binder_error { + struct binder_work work; + uint32_t cmd; +}; + +/** + * struct binder_node - binder node bookkeeping + * @debug_id: unique ID for debugging + * (invariant after initialized) + * @lock: lock for node fields + * @work: worklist element for node work + * (protected by @proc->inner_lock) + * @rb_node: element for proc->nodes tree + * (protected by @proc->inner_lock) + * @dead_node: element for binder_dead_nodes list + * (protected by binder_dead_nodes_lock) + * @proc: binder_proc that owns this node + * (invariant after initialized) + * @refs: list of references on this node + * (protected by @lock) + * @internal_strong_refs: used to take strong references when + * initiating a transaction + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_weak_refs: weak user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_strong_refs: strong user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @tmp_refs: temporary kernel refs + * (protected by @proc->inner_lock while @proc + * is valid, and by binder_dead_nodes_lock + * if @proc is NULL. During inc/dec and node release + * it is also protected by @lock to provide safety + * as the node dies and @proc becomes NULL) + * @ptr: userspace pointer for node + * (invariant, no lock needed) + * @cookie: userspace cookie for node + * (invariant, no lock needed) + * @has_strong_ref: userspace notified of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_strong_ref: userspace has acked notification of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_weak_ref: userspace notified of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_weak_ref: userspace has acked notification of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_async_transaction: async transaction to node in progress + * (protected by @lock) + * @sched_policy: minimum scheduling policy for node + * (invariant after initialized) + * @accept_fds: file descriptor operations supported for node + * (invariant after initialized) + * @min_priority: minimum scheduling priority + * (invariant after initialized) + * @inherit_rt: inherit RT scheduling policy from caller + * @txn_security_ctx: require sender's security context + * (invariant after initialized) + * @async_todo: list of async work items + * (protected by @proc->inner_lock) + * + * Bookkeeping structure for binder nodes. + */ struct binder_node { int debug_id; + spinlock_t lock; struct binder_work work; union { struct rb_node rb_node; @@ -273,99 +331,217 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; + int tmp_refs; binder_uintptr_t ptr; binder_uintptr_t cookie; - unsigned has_strong_ref:1; - unsigned pending_strong_ref:1; - unsigned has_weak_ref:1; - unsigned pending_weak_ref:1; - unsigned has_async_transaction:1; - unsigned accept_fds:1; - unsigned min_priority:8; + struct { + /* + * bitfield elements protected by + * proc inner_lock + */ + u8 has_strong_ref:1; + u8 pending_strong_ref:1; + u8 has_weak_ref:1; + u8 pending_weak_ref:1; + }; + struct { + /* + * invariant after initialization + */ + u8 sched_policy:2; + u8 inherit_rt:1; + u8 accept_fds:1; + u8 txn_security_ctx:1; + u8 min_priority; + }; + bool has_async_transaction; struct list_head async_todo; }; struct binder_ref_death { + /** + * @work: worklist element for death notifications + * (protected by inner_lock of the proc that + * this ref belongs to) + */ struct binder_work work; binder_uintptr_t cookie; }; +/** + * struct binder_ref_data - binder_ref counts and id + * @debug_id: unique ID for the ref + * @desc: unique userspace handle for ref + * @strong: strong ref count (debugging only if not locked) + * @weak: weak ref count (debugging only if not locked) + * + * Structure to hold ref count and ref id information. Since + * the actual ref can only be accessed with a lock, this structure + * is used to return information about the ref to callers of + * ref inc/dec functions. + */ +struct binder_ref_data { + int debug_id; + uint32_t desc; + int strong; + int weak; +}; + +/** + * struct binder_ref - struct to track references on nodes + * @data: binder_ref_data containing id, handle, and current refcounts + * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree + * @rb_node_node: node for lookup by @node in proc's rb_tree + * @node_entry: list entry for node->refs list in target node + * (protected by @node->lock) + * @proc: binder_proc containing ref + * @node: binder_node of target node. When cleaning up a + * ref for deletion in binder_cleanup_ref, a non-NULL + * @node indicates the node must be freed + * @death: pointer to death notification (ref_death) if requested + * (protected by @node->lock) + * + * Structure to track references from procA to target node (on procB). This + * structure is unsafe to access without holding @proc->outer_lock. + */ struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ - int debug_id; + struct binder_ref_data data; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; struct binder_node *node; - uint32_t desc; - int strong; - int weak; struct binder_ref_death *death; }; -struct binder_buffer { - struct list_head entry; /* free and allocated entries by address */ - struct rb_node rb_node; /* free entry by size or allocated entry */ - /* by address */ - unsigned free:1; - unsigned allow_user_free:1; - unsigned async_transaction:1; - unsigned debug_id:29; - - struct binder_transaction *transaction; - - struct binder_node *target_node; - size_t data_size; - size_t offsets_size; - size_t extra_buffers_size; - void *data; -}; - enum binder_deferred_state { BINDER_DEFERRED_PUT_FILES = 0x01, BINDER_DEFERRED_FLUSH = 0x02, BINDER_DEFERRED_RELEASE = 0x04, }; +/** + * struct binder_priority - scheduler policy and priority + * @sched_policy scheduler policy + * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT + * + * The binder driver supports inheriting the following scheduler policies: + * SCHED_NORMAL + * SCHED_BATCH + * SCHED_FIFO + * SCHED_RR + */ +struct binder_priority { + unsigned int sched_policy; + int prio; +}; + +/** + * struct binder_proc - binder process bookkeeping + * @proc_node: element for binder_procs list + * @threads: rbtree of binder_threads in this proc + * (protected by @inner_lock) + * @nodes: rbtree of binder nodes associated with + * this proc ordered by node->ptr + * (protected by @inner_lock) + * @refs_by_desc: rbtree of refs ordered by ref->desc + * (protected by @outer_lock) + * @refs_by_node: rbtree of refs ordered by ref->node + * (protected by @outer_lock) + * @waiting_threads: threads currently waiting for proc work + * (protected by @inner_lock) + * @pid PID of group_leader of process + * (invariant after initialized) + * @tsk task_struct for group_leader of process + * (invariant after initialized) + * @files files_struct for process + * (protected by @files_lock) + * @files_lock mutex to protect @files + * @deferred_work_node: element for binder_deferred_list + * (protected by binder_deferred_lock) + * @deferred_work: bitmap of deferred work to perform + * (protected by binder_deferred_lock) + * @outstanding_txns: number of transactions to be transmitted before + * processes in freeze_wait are woken up + * (protected by @inner_lock) + * @is_dead: process is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @inner_lock) + * @sync_recv: process received sync transactions since last frozen + * (protected by @inner_lock) + * @async_recv: process received async transactions since last frozen + * (protected by @inner_lock) + * @freeze_wait: waitqueue of processes waiting for all outstanding + * transactions to be processed + * (protected by @inner_lock) + * @todo: list of work for this process + * (protected by @inner_lock) + * @stats: per-process binder statistics + * (atomics, no lock needed) + * @delivered_death: list of delivered death notification + * (protected by @inner_lock) + * @max_threads: cap on number of binder threads + * (protected by @inner_lock) + * @requested_threads: number of binder threads requested but not + * yet started. In current implementation, can + * only be 0 or 1. + * (protected by @inner_lock) + * @requested_threads_started: number binder threads started + * (protected by @inner_lock) + * @tmp_ref: temporary reference to indicate proc is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @default_priority: default scheduler priority + * (invariant after initialized) + * @debugfs_entry: debugfs node + * @alloc: binder allocator bookkeeping + * @context: binder_context for this proc + * (invariant after initialized) + * @inner_lock: can nest under outer_lock and/or node lock + * @outer_lock: no nesting under innor or node lock + * Lock order: 1) outer, 2) node, 3) inner + * @binderfs_entry: process-specific binderfs log file + * + * Bookkeeping structure for binder processes + */ struct binder_proc { struct hlist_node proc_node; struct rb_root threads; struct rb_root nodes; struct rb_root refs_by_desc; struct rb_root refs_by_node; + struct list_head waiting_threads; int pid; - struct vm_area_struct *vma; - struct mm_struct *vma_vm_mm; struct task_struct *tsk; struct files_struct *files; + struct mutex files_lock; struct hlist_node deferred_work_node; int deferred_work; - void *buffer; - ptrdiff_t user_buffer_offset; - - struct list_head buffers; - struct rb_root free_buffers; - struct rb_root allocated_buffers; - size_t free_async_space; + int outstanding_txns; + bool is_dead; + bool is_frozen; + bool sync_recv; + bool async_recv; + wait_queue_head_t freeze_wait; - struct page **pages; - size_t buffer_size; - uint32_t buffer_free; struct list_head todo; - wait_queue_head_t wait; struct binder_stats stats; struct list_head delivered_death; int max_threads; int requested_threads; int requested_threads_started; - int ready_threads; - long default_priority; + atomic_t tmp_ref; + struct binder_priority default_priority; struct dentry *debugfs_entry; + struct binder_alloc alloc; struct binder_context *context; + spinlock_t inner_lock; + spinlock_t outer_lock; + struct dentry *binderfs_entry; }; enum { @@ -374,22 +550,63 @@ enum { BINDER_LOOPER_STATE_EXITED = 0x04, BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, - BINDER_LOOPER_STATE_NEED_RETURN = 0x20 + BINDER_LOOPER_STATE_POLL = 0x20, }; +/** + * struct binder_thread - binder thread bookkeeping + * @proc: binder process for this thread + * (invariant after initialization) + * @rb_node: element for proc->threads rbtree + * (protected by @proc->inner_lock) + * @waiting_thread_node: element for @proc->waiting_threads list + * (protected by @proc->inner_lock) + * @pid: PID for this thread + * (invariant after initialization) + * @looper: bitmap of looping state + * (only accessed by this thread) + * @looper_needs_return: looping thread needs to exit driver + * (no lock needed) + * @transaction_stack: stack of in-progress transactions for this thread + * (protected by @proc->inner_lock) + * @todo: list of work to do for this thread + * (protected by @proc->inner_lock) + * @process_todo: whether work in @todo should be processed + * (protected by @proc->inner_lock) + * @return_error: transaction errors reported by this thread + * (only accessed by this thread) + * @reply_error: transaction errors reported by target thread + * (protected by @proc->inner_lock) + * @wait: wait queue for thread work + * @stats: per-thread statistics + * (atomics, no lock needed) + * @tmp_ref: temporary reference to indicate thread is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @is_dead: thread is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @proc->inner_lock) + * @task: struct task_struct for this thread + * + * Bookkeeping structure for binder threads. + */ struct binder_thread { struct binder_proc *proc; struct rb_node rb_node; + struct list_head waiting_thread_node; int pid; - int looper; + int looper; /* only modified by this thread */ + bool looper_need_return; /* can be written by other thread */ struct binder_transaction *transaction_stack; struct list_head todo; - uint32_t return_error; /* Write failed, return error code in read buf */ - uint32_t return_error2; /* Write failed, return error code in read */ - /* buffer. Used when sending a reply to a dead process that */ - /* we are also waiting on */ + bool process_todo; + struct binder_error return_error; + struct binder_error reply_error; wait_queue_head_t wait; struct binder_stats stats; + atomic_t tmp_ref; + bool is_dead; + struct task_struct *task; }; struct binder_transaction { @@ -406,34 +623,305 @@ struct binder_transaction { struct binder_buffer *buffer; unsigned int code; unsigned int flags; - long priority; - long saved_priority; + struct binder_priority priority; + struct binder_priority saved_priority; + bool set_priority_called; kuid_t sender_euid; + binder_uintptr_t security_ctx; + /** + * @lock: protects @from, @to_proc, and @to_thread + * + * @from, @to_proc, and @to_thread can be set to NULL + * during thread teardown + */ + spinlock_t lock; }; +/** + * binder_proc_lock() - Acquire outer lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Acquires proc->outer_lock. Used to protect binder_ref + * structures associated with the given proc. + */ +#define binder_proc_lock(proc) _binder_proc_lock(proc, __LINE__) +static void +_binder_proc_lock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&proc->outer_lock); +} + +/** + * binder_proc_unlock() - Release spinlock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Release lock acquired via binder_proc_lock() + */ +#define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__) +static void +_binder_proc_unlock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&proc->outer_lock); +} + +/** + * binder_inner_proc_lock() - Acquire inner lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Acquires proc->inner_lock. Used to protect todo lists + */ +#define binder_inner_proc_lock(proc) _binder_inner_proc_lock(proc, __LINE__) +static void +_binder_inner_proc_lock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&proc->inner_lock); +} + +/** + * binder_inner_proc_unlock() - Release inner lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Release lock acquired via binder_inner_proc_lock() + */ +#define binder_inner_proc_unlock(proc) _binder_inner_proc_unlock(proc, __LINE__) +static void +_binder_inner_proc_unlock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&proc->inner_lock); +} + +/** + * binder_node_lock() - Acquire spinlock for given binder_node + * @node: struct binder_node to acquire + * + * Acquires node->lock. Used to protect binder_node fields + */ +#define binder_node_lock(node) _binder_node_lock(node, __LINE__) +static void +_binder_node_lock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&node->lock); +} + +/** + * binder_node_unlock() - Release spinlock for given binder_proc + * @node: struct binder_node to acquire + * + * Release lock acquired via binder_node_lock() + */ +#define binder_node_unlock(node) _binder_node_unlock(node, __LINE__) +static void +_binder_node_unlock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&node->lock); +} + +/** + * binder_node_inner_lock() - Acquire node and inner locks + * @node: struct binder_node to acquire + * + * Acquires node->lock. If node->proc also acquires + * proc->inner_lock. Used to protect binder_node fields + */ +#define binder_node_inner_lock(node) _binder_node_inner_lock(node, __LINE__) +static void +_binder_node_inner_lock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&node->lock); + if (node->proc) + binder_inner_proc_lock(node->proc); +} + +/** + * binder_node_unlock() - Release node and inner locks + * @node: struct binder_node to acquire + * + * Release lock acquired via binder_node_lock() + */ +#define binder_node_inner_unlock(node) _binder_node_inner_unlock(node, __LINE__) +static void +_binder_node_inner_unlock(struct binder_node *node, int line) +{ + struct binder_proc *proc = node->proc; + + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + if (proc) + binder_inner_proc_unlock(proc); + spin_unlock(&node->lock); +} + +static bool binder_worklist_empty_ilocked(struct list_head *list) +{ + return list_empty(list); +} + +/** + * binder_worklist_empty() - Check if no items on the work list + * @proc: binder_proc associated with list + * @list: list to check + * + * Return: true if there are no items on list, else false + */ +static bool binder_worklist_empty(struct binder_proc *proc, + struct list_head *list) +{ + bool ret; + + binder_inner_proc_lock(proc); + ret = binder_worklist_empty_ilocked(list); + binder_inner_proc_unlock(proc); + return ret; +} + +/** + * binder_enqueue_work_ilocked() - Add an item to the work list + * @work: struct binder_work to add to list + * @target_list: list to add work to + * + * Adds the work to the specified list. Asserts that work + * is not already on a list. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_work_ilocked(struct binder_work *work, + struct list_head *target_list) +{ + BUG_ON(target_list == NULL); + BUG_ON(work->entry.next && !list_empty(&work->entry)); + list_add_tail(&work->entry, target_list); +} + +/** + * binder_enqueue_deferred_thread_work_ilocked() - Add deferred thread work + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread. Doesn't set the process_todo + * flag, which means that (if it wasn't already set) the thread will go to + * sleep without handling this work when it calls read. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) +{ + WARN_ON(!list_empty(&thread->waiting_thread_node)); + binder_enqueue_work_ilocked(work, &thread->todo); +} + +/** + * binder_enqueue_thread_work_ilocked() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) +{ + WARN_ON(!list_empty(&thread->waiting_thread_node)); + binder_enqueue_work_ilocked(work, &thread->todo); + thread->process_todo = true; +} + +/** + * binder_enqueue_thread_work() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + */ +static void +binder_enqueue_thread_work(struct binder_thread *thread, + struct binder_work *work) +{ + binder_inner_proc_lock(thread->proc); + binder_enqueue_thread_work_ilocked(thread, work); + binder_inner_proc_unlock(thread->proc); +} + +static void +binder_dequeue_work_ilocked(struct binder_work *work) +{ + list_del_init(&work->entry); +} + +/** + * binder_dequeue_work() - Removes an item from the work list + * @proc: binder_proc associated with list + * @work: struct binder_work to remove from list + * + * Removes the specified work item from whatever list it is on. + * Can safely be called if work is not on any list. + */ +static void +binder_dequeue_work(struct binder_proc *proc, struct binder_work *work) +{ + binder_inner_proc_lock(proc); + binder_dequeue_work_ilocked(work); + binder_inner_proc_unlock(proc); +} + +static struct binder_work *binder_dequeue_work_head_ilocked( + struct list_head *list) +{ + struct binder_work *w; + + w = list_first_entry_or_null(list, struct binder_work, entry); + if (w) + list_del_init(&w->entry); + return w; +} + static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); +static void binder_free_thread(struct binder_thread *thread); +static void binder_free_proc(struct binder_proc *proc); +static void binder_inc_node_tmpref_ilocked(struct binder_node *node); static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = proc->files; unsigned long rlim_cur; unsigned long irqs; int ret; - if (files == NULL) - return -ESRCH; - - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; - + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + ret = -ESRCH; + goto err; + } + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; + } rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - preempt_enable_no_resched(); - ret = __alloc_fd(files, 0, rlim_cur, flags); - preempt_disable(); - + ret = __alloc_fd(proc->files, 0, rlim_cur, flags); +err: + mutex_unlock(&proc->files_lock); return ret; } @@ -443,11 +931,10 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { - if (proc->files) { - preempt_enable_no_resched(); + mutex_lock(&proc->files_lock); + if (proc->files) __fd_install(proc->files, fd, file); - preempt_disable(); - } + mutex_unlock(&proc->files_lock); } /* @@ -457,9 +944,11 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { int retval; - if (proc->files == NULL) - return -ESRCH; - + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + retval = -ESRCH; + goto err; + } retval = __close_fd(proc->files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || @@ -467,572 +956,287 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; - +err: + mutex_unlock(&proc->files_lock); return retval; } -static inline void binder_lock(struct binder_context *context, const char *tag) -{ - trace_binder_lock(tag); - mutex_lock(&context->binder_main_lock); - preempt_disable(); - trace_binder_locked(tag); -} - -static inline void binder_unlock(struct binder_context *context, - const char *tag) +static bool binder_has_work_ilocked(struct binder_thread *thread, + bool do_proc_work) { - trace_binder_unlock(tag); - mutex_unlock(&context->binder_main_lock); - preempt_enable(); + return thread->process_todo || + thread->looper_need_return || + (do_proc_work && + !binder_worklist_empty_ilocked(&thread->proc->todo)); } -static inline void *kzalloc_preempt_disabled(size_t size) +static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) { - void *ptr; + bool has_work; - ptr = kzalloc(size, GFP_NOWAIT); - if (ptr) - return ptr; + binder_inner_proc_lock(thread->proc); + has_work = binder_has_work_ilocked(thread, do_proc_work); + binder_inner_proc_unlock(thread->proc); - preempt_enable_no_resched(); - ptr = kzalloc(size, GFP_KERNEL); - preempt_disable(); + return has_work; +} - return ptr; +static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) +{ + return !thread->transaction_stack && + binder_worklist_empty_ilocked(&thread->todo) && + (thread->looper & (BINDER_LOOPER_STATE_ENTERED | + BINDER_LOOPER_STATE_REGISTERED)); } -static inline long copy_to_user_preempt_disabled(void __user *to, const void *from, long n) +static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, + bool sync) { - long ret; + struct rb_node *n; + struct binder_thread *thread; - preempt_enable_no_resched(); - ret = copy_to_user(to, from, n); - preempt_disable(); - return ret; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + thread = rb_entry(n, struct binder_thread, rb_node); + if (thread->looper & BINDER_LOOPER_STATE_POLL && + binder_available_for_proc_work_ilocked(thread)) { + if (sync) + wake_up_interruptible_sync(&thread->wait); + else + wake_up_interruptible(&thread->wait); + } + } } -static inline long copy_from_user_preempt_disabled(void *to, const void __user *from, long n) +/** + * binder_select_thread_ilocked() - selects a thread for doing proc work. + * @proc: process to select a thread from + * + * Note that calling this function moves the thread off the waiting_threads + * list, so it can only be woken up by the caller of this function, or a + * signal. Therefore, callers *should* always wake up the thread this function + * returns. + * + * Return: If there's a thread currently waiting for process work, + * returns that thread. Otherwise returns NULL. + */ +static struct binder_thread * +binder_select_thread_ilocked(struct binder_proc *proc) { - long ret; + struct binder_thread *thread; - preempt_enable_no_resched(); - ret = copy_from_user(to, from, n); - preempt_disable(); - return ret; -} + assert_spin_locked(&proc->inner_lock); + thread = list_first_entry_or_null(&proc->waiting_threads, + struct binder_thread, + waiting_thread_node); -#define get_user_preempt_disabled(x, ptr) \ -({ \ - int __ret; \ - preempt_enable_no_resched(); \ - __ret = get_user(x, ptr); \ - preempt_disable(); \ - __ret; \ -}) + if (thread) + list_del_init(&thread->waiting_thread_node); -#define put_user_preempt_disabled(x, ptr) \ -({ \ - int __ret; \ - preempt_enable_no_resched(); \ - __ret = put_user(x, ptr); \ - preempt_disable(); \ - __ret; \ -}) + return thread; +} -static void binder_set_nice(long nice) +/** + * binder_wakeup_thread_ilocked() - wakes up a thread for doing proc work. + * @proc: process to wake up a thread in + * @thread: specific thread to wake-up (may be NULL) + * @sync: whether to do a synchronous wake-up + * + * This function wakes up a thread in the @proc process. + * The caller may provide a specific thread to wake-up in + * the @thread parameter. If @thread is NULL, this function + * will wake up threads that have called poll(). + * + * Note that for this function to work as expected, callers + * should first call binder_select_thread() to find a thread + * to handle the work (if they don't have a thread already), + * and pass the result into the @thread parameter. + */ +static void binder_wakeup_thread_ilocked(struct binder_proc *proc, + struct binder_thread *thread, + bool sync) { - long min_nice; + assert_spin_locked(&proc->inner_lock); - if (can_nice(current, nice)) { - set_user_nice(current, nice); + if (thread) { + if (sync) + wake_up_interruptible_sync(&thread->wait); + else + wake_up_interruptible(&thread->wait); return; } - min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur; - binder_debug(BINDER_DEBUG_PRIORITY_CAP, - "%d: nice value %ld not allowed use %ld instead\n", - current->pid, nice, min_nice); - set_user_nice(current, min_nice); - if (min_nice < 20) - return; - binder_user_error("%d RLIMIT_NICE not set\n", current->pid); + + /* Didn't find a thread waiting for proc work; this can happen + * in two scenarios: + * 1. All threads are busy handling transactions + * In that case, one of those threads should call back into + * the kernel driver soon and pick up this work. + * 2. Threads are using the (e)poll interface, in which case + * they may be blocked on the waitqueue without having been + * added to waiting_threads. For this case, we just iterate + * over all threads not handling transaction work, and + * wake them all up. We wake all because we don't know whether + * a thread that called into (e)poll is handling non-binder + * work currently. + */ + binder_wakeup_poll_threads_ilocked(proc, sync); } -static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) +static void binder_wakeup_proc_ilocked(struct binder_proc *proc) { - return list_entry(buffer->entry.next, struct binder_buffer, entry); + struct binder_thread *thread = binder_select_thread_ilocked(proc); + + binder_wakeup_thread_ilocked(proc, thread, /* sync = */false); } -static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) +static bool is_rt_policy(int policy) { - return list_entry(buffer->entry.prev, struct binder_buffer, entry); + return policy == SCHED_FIFO || policy == SCHED_RR; } -static size_t binder_buffer_size(struct binder_proc *proc, - struct binder_buffer *buffer) +static bool is_fair_policy(int policy) { - if (list_is_last(&buffer->entry, &proc->buffers)) - return (u8 *)proc->buffer + - proc->buffer_size - (u8 *)buffer->data; - return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data; + return policy == SCHED_NORMAL || policy == SCHED_BATCH; } -static void binder_insert_free_buffer(struct binder_proc *proc, - struct binder_buffer *new_buffer) +static bool binder_supported_policy(int policy) { - struct rb_node **p = &proc->free_buffers.rb_node; - struct rb_node *parent = NULL; - struct binder_buffer *buffer; - size_t buffer_size; - size_t new_buffer_size; + return is_fair_policy(policy) || is_rt_policy(policy); +} - BUG_ON(!new_buffer->free); +static int to_userspace_prio(int policy, int kernel_priority) +{ + if (is_fair_policy(policy)) + return PRIO_TO_NICE(kernel_priority); + else + return MAX_USER_RT_PRIO - 1 - kernel_priority; +} - new_buffer_size = binder_buffer_size(proc, new_buffer); +static int to_kernel_prio(int policy, int user_priority) +{ + if (is_fair_policy(policy)) + return NICE_TO_PRIO(user_priority); + else + return MAX_USER_RT_PRIO - 1 - user_priority; +} - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: add free buffer, size %zd, at %pK\n", - proc->pid, new_buffer_size, new_buffer); - - while (*p) { - parent = *p; - buffer = rb_entry(parent, struct binder_buffer, rb_node); - BUG_ON(!buffer->free); - - buffer_size = binder_buffer_size(proc, buffer); - - if (new_buffer_size < buffer_size) - p = &parent->rb_left; - else - p = &parent->rb_right; - } - rb_link_node(&new_buffer->rb_node, parent, p); - rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); -} - -static void binder_insert_allocated_buffer(struct binder_proc *proc, - struct binder_buffer *new_buffer) +static void binder_do_set_priority(struct task_struct *task, + struct binder_priority desired, + bool verify) { - struct rb_node **p = &proc->allocated_buffers.rb_node; - struct rb_node *parent = NULL; - struct binder_buffer *buffer; - - BUG_ON(new_buffer->free); - - while (*p) { - parent = *p; - buffer = rb_entry(parent, struct binder_buffer, rb_node); - BUG_ON(buffer->free); - - if (new_buffer->data < buffer->data) - p = &parent->rb_left; - else if (new_buffer->data > buffer->data) - p = &parent->rb_right; - else - BUG(); - } - rb_link_node(&new_buffer->rb_node, parent, p); - rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); -} - -static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - uintptr_t user_ptr) -{ - struct rb_node *n = proc->allocated_buffers.rb_node; - struct binder_buffer *buffer; - void *kern_ptr; + int priority; /* user-space prio value */ + bool has_cap_nice; + unsigned int policy = desired.sched_policy; - kern_ptr = (void *)(user_ptr - proc->user_buffer_offset); - - while (n) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - BUG_ON(buffer->free); - - if (kern_ptr < buffer->data) - n = n->rb_left; - else if (kern_ptr > buffer->data) - n = n->rb_right; - else - return buffer; - } - return NULL; -} - -static int __binder_update_page_range(struct binder_proc *proc, int allocate, - void *start, void *end, - struct vm_area_struct *vma) -{ - void *page_addr; - unsigned long user_page_addr; - struct vm_struct tmp_area; - struct page **page; - struct mm_struct *mm; - - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: %s pages %pK-%pK\n", proc->pid, - allocate ? "allocate" : "free", start, end); - - if (end <= start) - return 0; + if (task->policy == policy && task->normal_prio == desired.prio) + return; - trace_binder_update_page_range(proc, allocate, start, end); + has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); - if (vma) - mm = NULL; - else - mm = get_task_mm(proc->tsk); + priority = to_userspace_prio(policy, desired.prio); - preempt_enable_no_resched(); + if (verify && is_rt_policy(policy) && !has_cap_nice) { + long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO); - if (mm) { - down_write(&mm->mmap_sem); - if (!mmget_still_valid(mm)) { - if (allocate == 0) - goto free_range; - goto err_no_vma; - } - vma = proc->vma; - if (vma && mm != proc->vma_vm_mm) { - pr_err("%d: vma mm and task mm mismatch\n", - proc->pid); - vma = NULL; + if (max_rtprio == 0) { + policy = SCHED_NORMAL; + priority = -20; + } else if (priority > max_rtprio) { + priority = max_rtprio; } } - if (allocate == 0) - goto free_range; - - if (vma == NULL) { - pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", - proc->pid); - goto err_no_vma; - } - - for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { - int ret; - struct page **page_array_ptr; - - page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + if (verify && is_fair_policy(policy) && !has_cap_nice) { + long min_nice = 20 - task_rlimit(task, RLIMIT_NICE); - BUG_ON(*page); - *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); - if (*page == NULL) { - pr_err("%d: binder_alloc_buf failed for page at %pK\n", - proc->pid, page_addr); - goto err_alloc_page_failed; - } - tmp_area.addr = page_addr; - tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */; - page_array_ptr = page; - ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr); - if (ret) { - pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", - proc->pid, page_addr); - goto err_map_kernel_failed; - } - user_page_addr = - (uintptr_t)page_addr + proc->user_buffer_offset; - ret = vm_insert_page(vma, user_page_addr, page[0]); - if (ret) { - pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", - proc->pid, user_page_addr); - goto err_vm_insert_page_failed; + if (min_nice > 19) { + binder_user_error("%d RLIMIT_NICE not set\n", + task->pid); + return; + } else if (priority < min_nice) { + priority = min_nice; } - /* vm_insert_page does not seem to increment the refcount */ - } - if (mm) { - up_write(&mm->mmap_sem); - mmput(mm); - } - - preempt_disable(); - - return 0; - -free_range: - for (page_addr = end - PAGE_SIZE; page_addr >= start; - page_addr -= PAGE_SIZE) { - page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; - if (vma) - zap_page_range(vma, (uintptr_t)page_addr + - proc->user_buffer_offset, PAGE_SIZE, NULL); -err_vm_insert_page_failed: - unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); -err_map_kernel_failed: - __free_page(*page); - *page = NULL; -err_alloc_page_failed: - ; - } -err_no_vma: - if (mm) { - up_write(&mm->mmap_sem); - mmput(mm); - } - - preempt_disable(); - - return -ENOMEM; -} - -static int binder_update_page_range(struct binder_proc *proc, int allocate, - void *start, void *end, - struct vm_area_struct *vma) -{ - /* - * For regular updates, move up start if needed since MIN_ALLOC pages - * are always mapped - */ - if (start - proc->buffer < BINDER_MIN_ALLOC) - start = proc->buffer + BINDER_MIN_ALLOC; - - return __binder_update_page_range(proc, allocate, start, end, vma); -} - -static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) -{ - struct rb_node *n = proc->free_buffers.rb_node; - struct binder_buffer *buffer; - size_t buffer_size; - struct rb_node *best_fit = NULL; - void *has_page_addr; - void *end_page_addr; - size_t size, data_offsets_size; - - if (proc->vma == NULL) { - pr_err("%d: binder_alloc_buf, no vma\n", - proc->pid); - return NULL; } - data_offsets_size = ALIGN(data_size, sizeof(void *)) + - ALIGN(offsets_size, sizeof(void *)); - - if (data_offsets_size < data_size || data_offsets_size < offsets_size) { - binder_user_error("%d: got transaction with invalid size %zd-%zd\n", - proc->pid, data_size, offsets_size); - return NULL; - } - size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); - if (size < data_offsets_size || size < extra_buffers_size) { - binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n", - proc->pid, extra_buffers_size); - return NULL; - } - if (is_async && - proc->free_async_space < size + sizeof(struct binder_buffer)) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd failed, no async space left\n", - proc->pid, size); - return NULL; - } + if (policy != desired.sched_policy || + to_kernel_prio(policy, priority) != desired.prio) + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: priority %d not allowed, using %d instead\n", + task->pid, desired.prio, + to_kernel_prio(policy, priority)); - /* Pad 0-size buffers so they get assigned unique addresses */ - size = max(size, sizeof(void *)); + /* Set the actual priority */ + if (task->policy != policy || is_rt_policy(policy)) { + struct sched_param params; - while (n) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - BUG_ON(!buffer->free); - buffer_size = binder_buffer_size(proc, buffer); + params.sched_priority = is_rt_policy(policy) ? priority : 0; - if (size < buffer_size) { - best_fit = n; - n = n->rb_left; - } else if (size > buffer_size) - n = n->rb_right; - else { - best_fit = n; - break; - } + sched_setscheduler_nocheck(task, + policy | SCHED_RESET_ON_FORK, + ¶ms); } - if (best_fit == NULL) { - pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", - proc->pid, size); - return NULL; - } - if (n == NULL) { - buffer = rb_entry(best_fit, struct binder_buffer, rb_node); - buffer_size = binder_buffer_size(proc, buffer); - } - - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", - proc->pid, size, buffer, buffer_size); - - has_page_addr = - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); - WARN_ON(n && buffer_size != size); - end_page_addr = - (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); - if (end_page_addr > has_page_addr) - end_page_addr = has_page_addr; - if (binder_update_page_range(proc, 1, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) - return NULL; - if (buffer_size != size) { - struct binder_buffer *new_buffer; - - new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (!new_buffer) { - pr_err("%s: %d failed to alloc new buffer struct\n", - __func__, proc->pid); - goto err_alloc_buf_struct_failed; - } - new_buffer->data = (u8 *)buffer->data + size; - list_add(&new_buffer->entry, &buffer->entry); - new_buffer->free = 1; - binder_insert_free_buffer(proc, new_buffer); - } - - rb_erase(best_fit, &proc->free_buffers); - buffer->free = 0; - binder_insert_allocated_buffer(proc, buffer); - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got %pK\n", - proc->pid, size, buffer); - buffer->data_size = data_size; - buffer->offsets_size = offsets_size; - buffer->extra_buffers_size = extra_buffers_size; - buffer->async_transaction = is_async; - if (is_async) { - proc->free_async_space -= size + sizeof(struct binder_buffer); - binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, - "%d: binder_alloc_buf size %zd async free %zd\n", - proc->pid, size, proc->free_async_space); - } - - return buffer; - -err_alloc_buf_struct_failed: - binder_update_page_range(proc, 0, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), - end_page_addr, NULL); - return NULL; -} - -static void *buffer_start_page(struct binder_buffer *buffer) -{ - return (void *)((uintptr_t)buffer->data & PAGE_MASK); + if (is_fair_policy(policy)) + set_user_nice(task, priority); } -static void *prev_buffer_end_page(struct binder_buffer *buffer) +static void binder_set_priority(struct task_struct *task, + struct binder_priority desired) { - return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK); + binder_do_set_priority(task, desired, /* verify = */ true); } -static void binder_delete_free_buffer(struct binder_proc *proc, - struct binder_buffer *buffer) +static void binder_restore_priority(struct task_struct *task, + struct binder_priority desired) { - struct binder_buffer *prev, *next = NULL; - bool to_free = true; - - BUG_ON(proc->buffers.next == &buffer->entry); - prev = binder_buffer_prev(buffer); - BUG_ON(!prev->free); - if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { - to_free = false; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK share page with %pK\n", - proc->pid, buffer->data, prev->data); - } - - if (!list_is_last(&buffer->entry, &proc->buffers)) { - next = binder_buffer_next(buffer); - if (buffer_start_page(next) == buffer_start_page(buffer)) { - to_free = false; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK share page with %pK\n", - proc->pid, - buffer->data, - next->data); - } - } - - if (PAGE_ALIGNED(buffer->data)) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer start %pK is page aligned\n", - proc->pid, buffer->data); - to_free = false; - } - - if (to_free) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK do not share page with %pK or %pK\n", - proc->pid, buffer->data, - prev->data, next->data); - binder_update_page_range(proc, 0, buffer_start_page(buffer), - buffer_start_page(buffer) + PAGE_SIZE, - NULL); - } - list_del(&buffer->entry); - kfree(buffer); + binder_do_set_priority(task, desired, /* verify = */ false); } -static void binder_free_buf(struct binder_proc *proc, - struct binder_buffer *buffer) +static void binder_transaction_priority(struct task_struct *task, + struct binder_transaction *t, + struct binder_priority node_prio, + bool inherit_rt) { - size_t size, buffer_size; - - buffer_size = binder_buffer_size(proc, buffer); - - size = ALIGN(buffer->data_size, sizeof(void *)) + - ALIGN(buffer->offsets_size, sizeof(void *)) + - ALIGN(buffer->extra_buffers_size, sizeof(void *)); + //bool inherit_fifo = t->buffer->target_node->proc->context->inherit_fifo_prio; + struct binder_priority desired_prio = t->priority; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_free_buf %pK size %zd buffer_size %zd\n", - proc->pid, buffer, size, buffer_size); - - BUG_ON(buffer->free); - BUG_ON(size > buffer_size); - BUG_ON(buffer->transaction != NULL); - BUG_ON(buffer->data < proc->buffer); - BUG_ON(buffer->data > proc->buffer + proc->buffer_size); + if (t->set_priority_called) + return; - if (buffer->async_transaction) { - proc->free_async_space += size + sizeof(struct binder_buffer); + t->set_priority_called = true; + t->saved_priority.sched_policy = task->policy; + t->saved_priority.prio = task->normal_prio; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, - "%d: binder_free_buf size %zd async free %zd\n", - proc->pid, size, proc->free_async_space); + if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { + desired_prio.prio = NICE_TO_PRIO(0); + desired_prio.sched_policy = SCHED_NORMAL; + } else { + desired_prio.prio = t->priority.prio; + desired_prio.sched_policy = t->priority.sched_policy; } - binder_update_page_range(proc, 0, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), - NULL); - rb_erase(&buffer->rb_node, &proc->allocated_buffers); - buffer->free = 1; - if (!list_is_last(&buffer->entry, &proc->buffers)) { - struct binder_buffer *next = binder_buffer_next(buffer); - - if (next->free) { - rb_erase(&next->rb_node, &proc->free_buffers); - binder_delete_free_buffer(proc, next); - } + if (node_prio.prio < t->priority.prio || + (node_prio.prio == t->priority.prio && + node_prio.sched_policy == SCHED_FIFO)) { + /* + * In case the minimum priority on the node is + * higher (lower value), use that priority. If + * the priority is the same, but the node uses + * SCHED_FIFO, prefer SCHED_FIFO, since it can + * run unbounded, unlike SCHED_RR. + */ + desired_prio = node_prio; } - if (proc->buffers.next != &buffer->entry) { - struct binder_buffer *prev = binder_buffer_prev(buffer); - if (prev->free) { - binder_delete_free_buffer(proc, buffer); - rb_erase(&prev->rb_node, &proc->free_buffers); - buffer = prev; - } - } - binder_insert_free_buffer(proc, buffer); + binder_set_priority(task, desired_prio); } -static struct binder_node *binder_get_node(struct binder_proc *proc, - binder_uintptr_t ptr) +static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc, + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; + assert_spin_locked(&proc->inner_lock); + while (n) { node = rb_entry(n, struct binder_node, rb_node); @@ -1040,21 +1244,47 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, n = n->rb_left; else if (ptr > node->ptr) n = n->rb_right; - else + else { + /* + * take an implicit weak reference + * to ensure node stays alive until + * call to binder_put_node() + */ + binder_inc_node_tmpref_ilocked(node); return node; + } } return NULL; } -static struct binder_node *binder_new_node(struct binder_proc *proc, - binder_uintptr_t ptr, - binder_uintptr_t cookie) +static struct binder_node *binder_get_node(struct binder_proc *proc, + binder_uintptr_t ptr) +{ + struct binder_node *node; + + binder_inner_proc_lock(proc); + node = binder_get_node_ilocked(proc, ptr); + binder_inner_proc_unlock(proc); + return node; +} + +static struct binder_node *binder_init_node_ilocked( + struct binder_proc *proc, + struct binder_node *new_node, + struct flat_binder_object *fp) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; struct binder_node *node; + binder_uintptr_t ptr = fp ? fp->binder : 0; + binder_uintptr_t cookie = fp ? fp->cookie : 0; + __u32 flags = fp ? fp->flags : 0; + s8 priority; + + assert_spin_locked(&proc->inner_lock); while (*p) { + parent = *p; node = rb_entry(parent, struct binder_node, rb_node); @@ -1062,14 +1292,19 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, p = &(*p)->rb_left; else if (ptr > node->ptr) p = &(*p)->rb_right; - else - return NULL; + else { + /* + * A matching node is already in + * the rb tree. Abandon the init + * and return it. + */ + binder_inc_node_tmpref_ilocked(node); + return node; + } } - - node = kzalloc_preempt_disabled(sizeof(*node)); - if (node == NULL) - return NULL; + node = new_node; binder_stats_created(BINDER_STAT_NODE); + node->tmp_refs++; rb_link_node(&node->rb_node, parent, p); rb_insert_color(&node->rb_node, &proc->nodes); node->debug_id = atomic_inc_return(&binder_last_id); @@ -1077,18 +1312,59 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, node->ptr = ptr; node->cookie = cookie; node->work.type = BINDER_WORK_NODE; + priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; + node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >> + FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT; + node->min_priority = to_kernel_prio(node->sched_policy, priority); + node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); + node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); + node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX); + spin_lock_init(&node->lock); INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, (u64)node->ptr, (u64)node->cookie); + return node; } -static int binder_inc_node(struct binder_node *node, int strong, int internal, - struct list_head *target_list) +static struct binder_node *binder_new_node(struct binder_proc *proc, + struct flat_binder_object *fp) +{ + struct binder_node *node; + struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL); + + if (!new_node) + return NULL; + binder_inner_proc_lock(proc); + node = binder_init_node_ilocked(proc, new_node, fp); + binder_inner_proc_unlock(proc); + if (node != new_node) + /* + * The node was already added by another thread + */ + kfree(new_node); + + return node; +} + +static void binder_free_node(struct binder_node *node) +{ + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); +} + +static int binder_inc_node_nilocked(struct binder_node *node, int strong, + int internal, + struct list_head *target_list) { + struct binder_proc *proc = node->proc; + + assert_spin_locked(&node->lock); + if (proc) + assert_spin_locked(&proc->inner_lock); if (strong) { if (internal) { if (target_list == NULL && @@ -1105,8 +1381,12 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, } else node->local_strong_refs++; if (!node->has_strong_ref && target_list) { - list_del_init(&node->work.entry); - list_add_tail(&node->work.entry, target_list); + struct binder_thread *thread = container_of(target_list, + struct binder_thread, todo); + binder_dequeue_work_ilocked(&node->work); + BUG_ON(&thread->todo != target_list); + binder_enqueue_deferred_thread_work_ilocked(thread, + &node->work); } } else { if (!internal) @@ -1117,58 +1397,172 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->debug_id); return -EINVAL; } - list_add_tail(&node->work.entry, target_list); + /* + * See comment above + */ + binder_enqueue_work_ilocked(&node->work, target_list); } } return 0; } -static int binder_dec_node(struct binder_node *node, int strong, int internal) +static int binder_inc_node(struct binder_node *node, int strong, int internal, + struct list_head *target_list) +{ + int ret; + + binder_node_inner_lock(node); + ret = binder_inc_node_nilocked(node, strong, internal, target_list); + binder_node_inner_unlock(node); + + return ret; +} + +static bool binder_dec_node_nilocked(struct binder_node *node, + int strong, int internal) { + struct binder_proc *proc = node->proc; + + assert_spin_locked(&node->lock); + if (proc) + assert_spin_locked(&proc->inner_lock); if (strong) { if (internal) node->internal_strong_refs--; else node->local_strong_refs--; if (node->local_strong_refs || node->internal_strong_refs) - return 0; + return false; } else { if (!internal) node->local_weak_refs--; - if (node->local_weak_refs || !hlist_empty(&node->refs)) - return 0; + if (node->local_weak_refs || node->tmp_refs || + !hlist_empty(&node->refs)) + return false; } - if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { + + if (proc && (node->has_strong_ref || node->has_weak_ref)) { if (list_empty(&node->work.entry)) { - list_add_tail(&node->work.entry, &node->proc->todo); - wake_up_interruptible(&node->proc->wait); + binder_enqueue_work_ilocked(&node->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); } } else { if (hlist_empty(&node->refs) && !node->local_strong_refs && - !node->local_weak_refs) { - list_del_init(&node->work.entry); - if (node->proc) { - rb_erase(&node->rb_node, &node->proc->nodes); + !node->local_weak_refs && !node->tmp_refs) { + if (proc) { + binder_dequeue_work_ilocked(&node->work); + rb_erase(&node->rb_node, &proc->nodes); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "refless node %d deleted\n", node->debug_id); } else { + BUG_ON(!list_empty(&node->work.entry)); + spin_lock(&binder_dead_nodes_lock); + /* + * tmp_refs could have changed so + * check it again + */ + if (node->tmp_refs) { + spin_unlock(&binder_dead_nodes_lock); + return false; + } hlist_del(&node->dead_node); + spin_unlock(&binder_dead_nodes_lock); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "dead node %d deleted\n", node->debug_id); } - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); + return true; } } + return false; +} - return 0; +static void binder_dec_node(struct binder_node *node, int strong, int internal) +{ + bool free_node; + + binder_node_inner_lock(node); + free_node = binder_dec_node_nilocked(node, strong, internal); + binder_node_inner_unlock(node); + if (free_node) + binder_free_node(node); } +static void binder_inc_node_tmpref_ilocked(struct binder_node *node) +{ + /* + * No call to binder_inc_node() is needed since we + * don't need to inform userspace of any changes to + * tmp_refs + */ + node->tmp_refs++; +} -static struct binder_ref *binder_get_ref(struct binder_proc *proc, - uint32_t desc, bool need_strong_ref) +/** + * binder_inc_node_tmpref() - take a temporary reference on node + * @node: node to reference + * + * Take reference on node to prevent the node from being freed + * while referenced only by a local variable. The inner lock is + * needed to serialize with the node work on the queue (which + * isn't needed after the node is dead). If the node is dead + * (node->proc is NULL), use binder_dead_nodes_lock to protect + * node->tmp_refs against dead-node-only cases where the node + * lock cannot be acquired (eg traversing the dead node list to + * print nodes) + */ +static void binder_inc_node_tmpref(struct binder_node *node) +{ + binder_node_lock(node); + if (node->proc) + binder_inner_proc_lock(node->proc); + else + spin_lock(&binder_dead_nodes_lock); + binder_inc_node_tmpref_ilocked(node); + if (node->proc) + binder_inner_proc_unlock(node->proc); + else + spin_unlock(&binder_dead_nodes_lock); + binder_node_unlock(node); +} + +/** + * binder_dec_node_tmpref() - remove a temporary reference on node + * @node: node to reference + * + * Release temporary reference on node taken via binder_inc_node_tmpref() + */ +static void binder_dec_node_tmpref(struct binder_node *node) +{ + bool free_node; + + binder_node_inner_lock(node); + if (!node->proc) + spin_lock(&binder_dead_nodes_lock); + node->tmp_refs--; + BUG_ON(node->tmp_refs < 0); + if (!node->proc) + spin_unlock(&binder_dead_nodes_lock); + /* + * Call binder_dec_node() to check if all refcounts are 0 + * and cleanup is needed. Calling with strong=0 and internal=1 + * causes no actual reference to be released in binder_dec_node(). + * If that changes, a change is needed here too. + */ + free_node = binder_dec_node_nilocked(node, 0, 1); + binder_node_inner_unlock(node); + if (free_node) + binder_free_node(node); +} + +static void binder_put_node(struct binder_node *node) +{ + binder_dec_node_tmpref(node); +} + +static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, + u32 desc, bool need_strong_ref) { struct rb_node *n = proc->refs_by_desc.rb_node; struct binder_ref *ref; @@ -1176,11 +1570,11 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, while (n) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (desc < ref->desc) { + if (desc < ref->data.desc) { n = n->rb_left; - } else if (desc > ref->desc) { + } else if (desc > ref->data.desc) { n = n->rb_right; - } else if (need_strong_ref && !ref->strong) { + } else if (need_strong_ref && !ref->data.strong) { binder_user_error("tried to use weak ref as strong ref\n"); return NULL; } else { @@ -1190,14 +1584,34 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, return NULL; } -static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, - struct binder_node *node) +/** + * binder_get_ref_for_node_olocked() - get the ref associated with given node + * @proc: binder_proc that owns the ref + * @node: binder_node of target + * @new_ref: newly allocated binder_ref to be initialized or %NULL + * + * Look up the ref for the given node and return it if it exists + * + * If it doesn't exist and the caller provides a newly allocated + * ref, initialize the fields of the newly allocated ref and insert + * into the given proc rb_trees and node refs list. + * + * Return: the ref for node. It is possible that another thread + * allocated/initialized the ref first in which case the + * returned ref would be different than the passed-in + * new_ref. new_ref must be kfree'd by the caller in + * this case. + */ +static struct binder_ref *binder_get_ref_for_node_olocked( + struct binder_proc *proc, + struct binder_node *node, + struct binder_ref *new_ref) { - struct rb_node *n; + struct binder_context *context = proc->context; struct rb_node **p = &proc->refs_by_node.rb_node; struct rb_node *parent = NULL; - struct binder_ref *ref, *new_ref; - struct binder_context *context = proc->context; + struct binder_ref *ref; + struct rb_node *n; while (*p) { parent = *p; @@ -1210,22 +1624,22 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, else return ref; } - new_ref = kzalloc_preempt_disabled(sizeof(*ref)); - if (new_ref == NULL) + if (!new_ref) return NULL; + binder_stats_created(BINDER_STAT_REF); - new_ref->debug_id = atomic_inc_return(&binder_last_id); + new_ref->data.debug_id = atomic_inc_return(&binder_last_id); new_ref->proc = proc; new_ref->node = node; rb_link_node(&new_ref->rb_node_node, parent, p); rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); - new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1; + new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (ref->desc > new_ref->desc) + if (ref->data.desc > new_ref->data.desc) break; - new_ref->desc = ref->desc + 1; + new_ref->data.desc = ref->data.desc + 1; } p = &proc->refs_by_desc.rb_node; @@ -1233,126 +1647,447 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_desc); - if (new_ref->desc < ref->desc) + if (new_ref->data.desc < ref->data.desc) p = &(*p)->rb_left; - else if (new_ref->desc > ref->desc) + else if (new_ref->data.desc > ref->data.desc) p = &(*p)->rb_right; else BUG(); } rb_link_node(&new_ref->rb_node_desc, parent, p); rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); - if (node) { - hlist_add_head(&new_ref->node_entry, &node->refs); - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for node %d\n", - proc->pid, new_ref->debug_id, new_ref->desc, - node->debug_id); - } else { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for dead node\n", - proc->pid, new_ref->debug_id, new_ref->desc); - } + binder_node_lock(node); + hlist_add_head(&new_ref->node_entry, &node->refs); + + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d new ref %d desc %d for node %d\n", + proc->pid, new_ref->data.debug_id, new_ref->data.desc, + node->debug_id); + binder_node_unlock(node); return new_ref; } -static void binder_delete_ref(struct binder_ref *ref) +static void binder_cleanup_ref_olocked(struct binder_ref *ref) { + bool delete_node = false; + binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d delete ref %d desc %d for node %d\n", - ref->proc->pid, ref->debug_id, ref->desc, + ref->proc->pid, ref->data.debug_id, ref->data.desc, ref->node->debug_id); rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); - if (ref->strong) - binder_dec_node(ref->node, 1, 1); + + binder_node_inner_lock(ref->node); + if (ref->data.strong) + binder_dec_node_nilocked(ref->node, 1, 1); + hlist_del(&ref->node_entry); - binder_dec_node(ref->node, 0, 1); + delete_node = binder_dec_node_nilocked(ref->node, 0, 1); + binder_node_inner_unlock(ref->node); + /* + * Clear ref->node unless we want the caller to free the node + */ + if (!delete_node) { + /* + * The caller uses ref->node to determine + * whether the node needs to be freed. Clear + * it since the node is still alive. + */ + ref->node = NULL; + } + if (ref->death) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "%d delete ref %d desc %d has death notification\n", - ref->proc->pid, ref->debug_id, ref->desc); - list_del(&ref->death->work.entry); - kfree(ref->death); + ref->proc->pid, ref->data.debug_id, + ref->data.desc); + binder_dequeue_work(ref->proc, &ref->death->work); binder_stats_deleted(BINDER_STAT_DEATH); } - kfree(ref); binder_stats_deleted(BINDER_STAT_REF); } -static int binder_inc_ref(struct binder_ref *ref, int strong, - struct list_head *target_list) +/** + * binder_inc_ref_olocked() - increment the ref for given handle + * @ref: ref to be incremented + * @strong: if true, strong increment, else weak + * @target_list: list to queue node work on + * + * Increment the ref. @ref->proc->outer_lock must be held on entry + * + * Return: 0, if successful, else errno + */ +static int binder_inc_ref_olocked(struct binder_ref *ref, int strong, + struct list_head *target_list) { int ret; if (strong) { - if (ref->strong == 0) { + if (ref->data.strong == 0) { ret = binder_inc_node(ref->node, 1, 1, target_list); if (ret) return ret; } - ref->strong++; + ref->data.strong++; } else { - if (ref->weak == 0) { + if (ref->data.weak == 0) { ret = binder_inc_node(ref->node, 0, 1, target_list); if (ret) return ret; } - ref->weak++; + ref->data.weak++; } return 0; } - -static int binder_dec_ref(struct binder_ref **ptr_to_ref, int strong) +/** + * binder_dec_ref() - dec the ref for given handle + * @ref: ref to be decremented + * @strong: if true, strong decrement, else weak + * + * Decrement the ref. + * + * Return: true if ref is cleaned up and ready to be freed + */ +static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong) { - struct binder_ref *ref = *ptr_to_ref; if (strong) { - if (ref->strong == 0) { + if (ref->data.strong == 0) { binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->debug_id, - ref->desc, ref->strong, ref->weak); - return -EINVAL; - } - ref->strong--; - if (ref->strong == 0) { - int ret; - - ret = binder_dec_node(ref->node, strong, 1); - if (ret) - return ret; + ref->proc->pid, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak); + return false; } + ref->data.strong--; + if (ref->data.strong == 0) + binder_dec_node(ref->node, strong, 1); } else { - if (ref->weak == 0) { + if (ref->data.weak == 0) { binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->debug_id, - ref->desc, ref->strong, ref->weak); - return -EINVAL; + ref->proc->pid, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak); + return false; } - ref->weak--; + ref->data.weak--; } - if (ref->strong == 0 && ref->weak == 0) { - binder_delete_ref(ref); - *ptr_to_ref = NULL; + if (ref->data.strong == 0 && ref->data.weak == 0) { + binder_cleanup_ref_olocked(ref); + return true; + } + return false; +} + +/** + * binder_get_node_from_ref() - get the node from the given proc/desc + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @need_strong_ref: if true, only return node if ref is strong + * @rdata: the id/refcount data for the ref + * + * Given a proc and ref handle, return the associated binder_node + * + * Return: a binder_node or NULL if not found or not strong when strong required + */ +static struct binder_node *binder_get_node_from_ref( + struct binder_proc *proc, + u32 desc, bool need_strong_ref, + struct binder_ref_data *rdata) +{ + struct binder_node *node; + struct binder_ref *ref; + + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, desc, need_strong_ref); + if (!ref) + goto err_no_ref; + node = ref->node; + /* + * Take an implicit reference on the node to ensure + * it stays alive until the call to binder_put_node() + */ + binder_inc_node_tmpref(node); + if (rdata) + *rdata = ref->data; + binder_proc_unlock(proc); + + return node; + +err_no_ref: + binder_proc_unlock(proc); + return NULL; +} + +/** + * binder_free_ref() - free the binder_ref + * @ref: ref to free + * + * Free the binder_ref. Free the binder_node indicated by ref->node + * (if non-NULL) and the binder_ref_death indicated by ref->death. + */ +static void binder_free_ref(struct binder_ref *ref) +{ + if (ref->node) + binder_free_node(ref->node); + kfree(ref->death); + kfree(ref); +} + +/** + * binder_update_ref_for_handle() - inc/dec the ref for given handle + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @increment: true=inc reference, false=dec reference + * @strong: true=strong reference, false=weak reference + * @rdata: the id/refcount data for the ref + * + * Given a proc and ref handle, increment or decrement the ref + * according to "increment" arg. + * + * Return: 0 if successful, else errno + */ +static int binder_update_ref_for_handle(struct binder_proc *proc, + uint32_t desc, bool increment, bool strong, + struct binder_ref_data *rdata) +{ + int ret = 0; + struct binder_ref *ref; + bool delete_ref = false; + + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, desc, strong); + if (!ref) { + ret = -EINVAL; + goto err_no_ref; + } + if (increment) + ret = binder_inc_ref_olocked(ref, strong, NULL); + else + delete_ref = binder_dec_ref_olocked(ref, strong); + + if (rdata) + *rdata = ref->data; + binder_proc_unlock(proc); + + if (delete_ref) + binder_free_ref(ref); + return ret; + +err_no_ref: + binder_proc_unlock(proc); + return ret; +} + +/** + * binder_dec_ref_for_handle() - dec the ref for given handle + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @strong: true=strong reference, false=weak reference + * @rdata: the id/refcount data for the ref + * + * Just calls binder_update_ref_for_handle() to decrement the ref. + * + * Return: 0 if successful, else errno + */ +static int binder_dec_ref_for_handle(struct binder_proc *proc, + uint32_t desc, bool strong, struct binder_ref_data *rdata) +{ + return binder_update_ref_for_handle(proc, desc, false, strong, rdata); +} + + +/** + * binder_inc_ref_for_node() - increment the ref for given proc/node + * @proc: proc containing the ref + * @node: target node + * @strong: true=strong reference, false=weak reference + * @target_list: worklist to use if node is incremented + * @rdata: the id/refcount data for the ref + * + * Given a proc and node, increment the ref. Create the ref if it + * doesn't already exist + * + * Return: 0 if successful, else errno + */ +static int binder_inc_ref_for_node(struct binder_proc *proc, + struct binder_node *node, + bool strong, + struct list_head *target_list, + struct binder_ref_data *rdata) +{ + struct binder_ref *ref; + struct binder_ref *new_ref = NULL; + int ret = 0; + + binder_proc_lock(proc); + ref = binder_get_ref_for_node_olocked(proc, node, NULL); + if (!ref) { + binder_proc_unlock(proc); + new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!new_ref) + return -ENOMEM; + binder_proc_lock(proc); + ref = binder_get_ref_for_node_olocked(proc, node, new_ref); + } + ret = binder_inc_ref_olocked(ref, strong, target_list); + *rdata = ref->data; + binder_proc_unlock(proc); + if (new_ref && ref != new_ref) + /* + * Another thread created the ref first so + * free the one we allocated + */ + kfree(new_ref); + return ret; +} + +static void binder_pop_transaction_ilocked(struct binder_thread *target_thread, + struct binder_transaction *t) +{ + BUG_ON(!target_thread); + assert_spin_locked(&target_thread->proc->inner_lock); + BUG_ON(target_thread->transaction_stack != t); + BUG_ON(target_thread->transaction_stack->from != target_thread); + target_thread->transaction_stack = + target_thread->transaction_stack->from_parent; + t->from = NULL; +} + +/** + * binder_thread_dec_tmpref() - decrement thread->tmp_ref + * @thread: thread to decrement + * + * A thread needs to be kept alive while being used to create or + * handle a transaction. binder_get_txn_from() is used to safely + * extract t->from from a binder_transaction and keep the thread + * indicated by t->from from being freed. When done with that + * binder_thread, this function is called to decrement the + * tmp_ref and free if appropriate (thread has been released + * and no transaction being processed by the driver) + */ +static void binder_thread_dec_tmpref(struct binder_thread *thread) +{ + /* + * atomic is used to protect the counter value while + * it cannot reach zero or thread->is_dead is false + */ + binder_inner_proc_lock(thread->proc); + atomic_dec(&thread->tmp_ref); + if (thread->is_dead && !atomic_read(&thread->tmp_ref)) { + binder_inner_proc_unlock(thread->proc); + binder_free_thread(thread); + return; + } + binder_inner_proc_unlock(thread->proc); +} + +/** + * binder_proc_dec_tmpref() - decrement proc->tmp_ref + * @proc: proc to decrement + * + * A binder_proc needs to be kept alive while being used to create or + * handle a transaction. proc->tmp_ref is incremented when + * creating a new transaction or the binder_proc is currently in-use + * by threads that are being released. When done with the binder_proc, + * this function is called to decrement the counter and free the + * proc if appropriate (proc has been released, all threads have + * been released and not currenly in-use to process a transaction). + */ +static void binder_proc_dec_tmpref(struct binder_proc *proc) +{ + binder_inner_proc_lock(proc); + atomic_dec(&proc->tmp_ref); + if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) && + !atomic_read(&proc->tmp_ref)) { + binder_inner_proc_unlock(proc); + binder_free_proc(proc); + return; + } + binder_inner_proc_unlock(proc); +} + +/** + * binder_get_txn_from() - safely extract the "from" thread in transaction + * @t: binder transaction for t->from + * + * Atomically return the "from" thread and increment the tmp_ref + * count for the thread to ensure it stays alive until + * binder_thread_dec_tmpref() is called. + * + * Return: the value of t->from + */ +static struct binder_thread *binder_get_txn_from( + struct binder_transaction *t) +{ + struct binder_thread *from; + + spin_lock(&t->lock); + from = t->from; + if (from) + atomic_inc(&from->tmp_ref); + spin_unlock(&t->lock); + return from; +} + +/** + * binder_get_txn_from_and_acq_inner() - get t->from and acquire inner lock + * @t: binder transaction for t->from + * + * Same as binder_get_txn_from() except it also acquires the proc->inner_lock + * to guarantee that the thread cannot be released while operating on it. + * The caller must call binder_inner_proc_unlock() to release the inner lock + * as well as call binder_dec_thread_txn() to release the reference. + * + * Return: the value of t->from + */ +static struct binder_thread *binder_get_txn_from_and_acq_inner( + struct binder_transaction *t) +{ + struct binder_thread *from; + + from = binder_get_txn_from(t); + if (!from) + return NULL; + binder_inner_proc_lock(from->proc); + if (t->from) { + BUG_ON(from != t->from); + return from; } - return 0; + binder_inner_proc_unlock(from->proc); + binder_thread_dec_tmpref(from); + return NULL; } -static void binder_pop_transaction(struct binder_thread *target_thread, - struct binder_transaction *t) +static void binder_free_transaction(struct binder_transaction *t) { - if (target_thread) { - BUG_ON(target_thread->transaction_stack != t); - BUG_ON(target_thread->transaction_stack->from != target_thread); - target_thread->transaction_stack = - target_thread->transaction_stack->from_parent; - t->from = NULL; + struct binder_proc *target_proc; + + spin_lock(&t->lock); + target_proc = t->to_proc; + if (target_proc) { + atomic_inc(&target_proc->tmp_ref); + spin_unlock(&t->lock); + + binder_inner_proc_lock(target_proc); + target_proc->outstanding_txns--; + BUG_ON(target_proc->outstanding_txns < 0); + if (!target_proc->outstanding_txns && target_proc->is_frozen) + wake_up_interruptible_all(&target_proc->freeze_wait); + if (t->buffer) + t->buffer->transaction = NULL; + binder_inner_proc_unlock(target_proc); + binder_proc_dec_tmpref(target_proc); + } else { + /* + * If the transaction has no target_proc, then + * t->buffer->transaction * has already been cleared. + */ + spin_unlock(&t->lock); } - t->need_reply = 0; - if (t->buffer) - t->buffer->transaction = NULL; kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); } @@ -1365,30 +2100,34 @@ static void binder_send_failed_reply(struct binder_transaction *t, BUG_ON(t->flags & TF_ONE_WAY); while (1) { - target_thread = t->from; + target_thread = binder_get_txn_from_and_acq_inner(t); if (target_thread) { - if (target_thread->return_error != BR_OK && - target_thread->return_error2 == BR_OK) { - target_thread->return_error2 = - target_thread->return_error; - target_thread->return_error = BR_OK; - } - if (target_thread->return_error == BR_OK) { - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "send failed reply for transaction %d to %d:%d\n", - t->debug_id, - target_thread->proc->pid, - target_thread->pid); - - binder_pop_transaction(target_thread, t); - target_thread->return_error = error_code; + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "send failed reply for transaction %d to %d:%d\n", + t->debug_id, + target_thread->proc->pid, + target_thread->pid); + + binder_pop_transaction_ilocked(target_thread, t); + if (target_thread->reply_error.cmd == BR_OK) { + target_thread->reply_error.cmd = error_code; + binder_enqueue_thread_work_ilocked( + target_thread, + &target_thread->reply_error.work); wake_up_interruptible(&target_thread->wait); } else { - pr_err("reply failed, target thread, %d:%d, has error code %d already\n", - target_thread->proc->pid, - target_thread->pid, - target_thread->return_error); + /* + * Cannot get here for normal operation, but + * we can if multiple synchronous transactions + * are sent without blocking for responses. + * Just ignore the 2nd error in this case. + */ + pr_warn("Unexpected reply error: %u\n", + target_thread->reply_error.cmd); } + binder_inner_proc_unlock(target_thread->proc); + binder_thread_dec_tmpref(target_thread); + binder_free_transaction(t); return; } next = t->from_parent; @@ -1397,7 +2136,7 @@ static void binder_send_failed_reply(struct binder_transaction *t, "send failed reply for transaction %d, target dead\n", t->debug_id); - binder_pop_transaction(target_thread, t); + binder_free_transaction(t); if (next == NULL) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "reply failed, no target thread at root\n"); @@ -1410,6 +2149,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, } } +/** + * binder_cleanup_transaction() - cleans up undelivered transaction + * @t: transaction that needs to be cleaned up + * @reason: reason the transaction wasn't delivered + * @error_code: error to return to caller (if synchronous call) + */ +static void binder_cleanup_transaction(struct binder_transaction *t, + const char *reason, + uint32_t error_code) +{ + if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) { + binder_send_failed_reply(t, error_code); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered transaction %d, %s\n", + t->debug_id, reason); + binder_free_transaction(t); + } +} + /** * binder_validate_object() - checks for a valid metadata object in a buffer. * @buffer: binder_buffer that we're parsing. @@ -1424,8 +2183,8 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) struct binder_object_header *hdr; size_t object_size = 0; - if (offset > buffer->data_size - sizeof(*hdr) || - buffer->data_size < sizeof(*hdr) || + if (buffer->data_size < sizeof(*hdr) || + offset > buffer->data_size - sizeof(*hdr) || !IS_ALIGNED(offset, sizeof(u32))) return 0; @@ -1557,6 +2316,66 @@ static bool binder_validate_fixup(struct binder_buffer *b, return (fixup_offset >= last_min_offset); } +/** + * struct binder_task_work_cb - for deferred close + * + * @twork: callback_head for task work + * @fd: fd to close + * + * Structure to pass task work to be handled after + * returning from binder_ioctl() via task_work_add(). + */ +struct binder_task_work_cb { + struct callback_head twork; + struct file *file; +}; + +/** + * binder_do_fd_close() - close list of file descriptors + * @twork: callback head for task work + * + * It is not safe to call ksys_close() during the binder_ioctl() + * function if there is a chance that binder's own file descriptor + * might be closed. This is to meet the requirements for using + * fdget() (see comments for __fget_light()). Therefore use + * task_work_add() to schedule the close operation once we have + * returned from binder_ioctl(). This function is a callback + * for that mechanism and does the actual ksys_close() on the + * given file descriptor. + */ +static void binder_do_fd_close(struct callback_head *twork) +{ + struct binder_task_work_cb *twcb = container_of(twork, + struct binder_task_work_cb, twork); + + fput(twcb->file); + kfree(twcb); +} + +/** + * binder_deferred_fd_close() - schedule a close for the given file-descriptor + * @fd: file-descriptor to close + * + * See comments in binder_do_fd_close(). This function is used to schedule + * a file-descriptor to be closed after returning from binder_ioctl(). + */ +static void binder_deferred_fd_close(int fd) +{ + struct binder_task_work_cb *twcb; + + twcb = kzalloc(sizeof(*twcb), GFP_KERNEL); + if (!twcb) + return; + init_task_work(&twcb->twork, binder_do_fd_close); + __close_fd_get_file(fd, &twcb->file); + if (twcb->file) { + filp_close(twcb->file, current->files); + task_work_add(current, &twcb->twork, true); + } else { + kfree(twcb); + } +} + static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, binder_size_t *failed_at) @@ -1606,24 +2425,26 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, node->debug_id, (u64)node->ptr); binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, 0); + binder_put_node(node); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct flat_binder_object *fp; - struct binder_ref *ref; + struct binder_ref_data rdata; + int ret; fp = to_flat_binder_object(hdr); - ref = binder_get_ref(proc, fp->handle, - hdr->type == BINDER_TYPE_HANDLE); - if (ref == NULL) { - pr_err("transaction release %d bad handle %d\n", - debug_id, fp->handle); + ret = binder_dec_ref_for_handle(proc, fp->handle, + hdr->type == BINDER_TYPE_HANDLE, &rdata); + + if (ret) { + pr_err("transaction release %d bad handle %d, ret = %d\n", + debug_id, fp->handle, ret); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, ref->node->debug_id); - binder_dec_ref(&ref, hdr->type == BINDER_TYPE_HANDLE); + " ref %d desc %d\n", + rdata.debug_id, rdata.desc); } break; case BINDER_TYPE_FD: { @@ -1662,7 +2483,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * back to kernel address space to access it */ parent_buffer = parent->buffer - - proc->user_buffer_offset; + binder_alloc_get_user_buffer_offset( + &proc->alloc); fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { @@ -1677,9 +2499,10 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, debug_id, (u64)fda->num_fds); continue; } - fd_array = (u32 *)(parent_buffer + fda->parent_offset); + fd_array = (u32 *)(uintptr_t) + (parent_buffer + fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) - task_close_fd(proc, fd_array[fd_index]); + binder_deferred_fd_close(fd_array[fd_index]); } break; default: pr_err("transaction release %d bad object type %x\n", @@ -1694,102 +2517,121 @@ static int binder_translate_binder(struct flat_binder_object *fp, struct binder_thread *thread) { struct binder_node *node; - struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; + struct binder_ref_data rdata; + int ret = 0; node = binder_get_node(proc, fp->binder); if (!node) { - node = binder_new_node(proc, fp->binder, fp->cookie); + node = binder_new_node(proc, fp); if (!node) return -ENOMEM; - - node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; - node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, (u64)fp->binder, node->debug_id, (u64)fp->cookie, (u64)node->cookie); - return -EINVAL; + ret = -EINVAL; + goto done; + } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + ret = -EPERM; + goto done; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) - return -EPERM; - ref = binder_get_ref_for_node(target_proc, node); - if (!ref) - return -EINVAL; + ret = binder_inc_ref_for_node(target_proc, node, + fp->hdr.type == BINDER_TYPE_BINDER, + &thread->todo, &rdata); + if (ret) + goto done; if (fp->hdr.type == BINDER_TYPE_BINDER) fp->hdr.type = BINDER_TYPE_HANDLE; else fp->hdr.type = BINDER_TYPE_WEAK_HANDLE; fp->binder = 0; - fp->handle = ref->desc; + fp->handle = rdata.desc; fp->cookie = 0; - binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo); - trace_binder_transaction_node_to_ref(t, node, ref); + trace_binder_transaction_node_to_ref(t, node, &rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " node %d u%016llx -> ref %d desc %d\n", node->debug_id, (u64)node->ptr, - ref->debug_id, ref->desc); - - return 0; + rdata.debug_id, rdata.desc); +done: + binder_put_node(node); + return ret; } static int binder_translate_handle(struct flat_binder_object *fp, struct binder_transaction *t, struct binder_thread *thread) { - struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; + struct binder_node *node; + struct binder_ref_data src_rdata; + int ret = 0; - ref = binder_get_ref(proc, fp->handle, - fp->hdr.type == BINDER_TYPE_HANDLE); - if (!ref) { + node = binder_get_node_from_ref(proc, fp->handle, + fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); + if (!node) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, thread->pid, fp->handle); return -EINVAL; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) - return -EPERM; + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + ret = -EPERM; + goto done; + } - if (ref->node->proc == target_proc) { + binder_node_lock(node); + if (node->proc == target_proc) { if (fp->hdr.type == BINDER_TYPE_HANDLE) fp->hdr.type = BINDER_TYPE_BINDER; else fp->hdr.type = BINDER_TYPE_WEAK_BINDER; - fp->binder = ref->node->ptr; - fp->cookie = ref->node->cookie; - binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER, - 0, NULL); - trace_binder_transaction_ref_to_node(t, ref); + fp->binder = node->ptr; + fp->cookie = node->cookie; + if (node->proc) + binder_inner_proc_lock(node->proc); + binder_inc_node_nilocked(node, + fp->hdr.type == BINDER_TYPE_BINDER, + 0, NULL); + if (node->proc) + binder_inner_proc_unlock(node->proc); + trace_binder_transaction_ref_to_node(t, node, &src_rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> node %d u%016llx\n", - ref->debug_id, ref->desc, ref->node->debug_id, - (u64)ref->node->ptr); + src_rdata.debug_id, src_rdata.desc, node->debug_id, + (u64)node->ptr); + binder_node_unlock(node); } else { - struct binder_ref *new_ref; + struct binder_ref_data dest_rdata; - new_ref = binder_get_ref_for_node(target_proc, ref->node); - if (!new_ref) - return -EINVAL; + binder_node_unlock(node); + ret = binder_inc_ref_for_node(target_proc, node, + fp->hdr.type == BINDER_TYPE_HANDLE, + NULL, &dest_rdata); + if (ret) + goto done; fp->binder = 0; - fp->handle = new_ref->desc; + fp->handle = dest_rdata.desc; fp->cookie = 0; - binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE, - NULL); - trace_binder_transaction_ref_to_ref(t, ref, new_ref); + trace_binder_transaction_ref_to_ref(t, node, &src_rdata, + &dest_rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, new_ref->debug_id, - new_ref->desc, ref->node->debug_id); + src_rdata.debug_id, src_rdata.desc, + dest_rdata.debug_id, dest_rdata.desc, + node->debug_id); } - return 0; +done: + binder_put_node(node); + return ret; } static int binder_translate_fd(int fd, @@ -1880,8 +2722,9 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, * Since the parent was already fixed up, convert it * back to the kernel address space to access it */ - parent_buffer = parent->buffer - target_proc->user_buffer_offset; - fd_array = (u32 *)(parent_buffer + fda->parent_offset); + parent_buffer = parent->buffer - + binder_alloc_get_user_buffer_offset(&target_proc->alloc); + fd_array = (u32 *)(uintptr_t)(parent_buffer + fda->parent_offset); if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { binder_user_error("%d:%d parent offset not aligned correctly.\n", proc->pid, thread->pid); @@ -1947,13 +2790,134 @@ static int binder_fixup_parent(struct binder_transaction *t, proc->pid, thread->pid); return -EINVAL; } - parent_buffer = (u8 *)(parent->buffer - - target_proc->user_buffer_offset); + parent_buffer = (u8 *)(uintptr_t)(parent->buffer - + binder_alloc_get_user_buffer_offset( + &target_proc->alloc)); *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; return 0; } +/** + * binder_proc_transaction() - sends a transaction to a process and wakes it up + * @t: transaction to send + * @proc: process to send the transaction to + * @thread: thread in @proc to send the transaction to (may be NULL) + * + * This function queues a transaction to the specified process. It will try + * to find a thread in the target process to handle the transaction and + * wake it up. If no thread is found, the work is queued to the proc + * waitqueue. + * + * If the @thread parameter is not NULL, the transaction is always queued + * to the waitlist of that specific thread. + * + * Return: 0 if the transaction was successfully queued + * BR_DEAD_REPLY if the target process or thread is dead + * BR_FROZEN_REPLY if the target process or thread is frozen + */ +static int binder_proc_transaction(struct binder_transaction *t, + struct binder_proc *proc, + struct binder_thread *thread) +{ + struct binder_node *node = t->buffer->target_node; + struct binder_priority node_prio; + bool oneway = !!(t->flags & TF_ONE_WAY); + bool pending_async = false; + + BUG_ON(!node); + binder_node_lock(node); + node_prio.prio = node->min_priority; + node_prio.sched_policy = node->sched_policy; + + if (oneway) { + BUG_ON(thread); + if (node->has_async_transaction) + pending_async = true; + else + node->has_async_transaction = true; + } + + binder_inner_proc_lock(proc); + if (proc->is_frozen) { + proc->sync_recv |= !oneway; + proc->async_recv |= oneway; + } + + if ((proc->is_frozen && !oneway) || proc->is_dead || + (thread && thread->is_dead)) { + bool proc_is_dead = proc->is_dead + || (thread && thread->is_dead); + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + return proc_is_dead ? BR_DEAD_REPLY : BR_FROZEN_REPLY; + } + + if (!thread && !pending_async) + thread = binder_select_thread_ilocked(proc); + + if (thread) { + binder_transaction_priority(thread->task, t, node_prio, + node->inherit_rt); + binder_enqueue_thread_work_ilocked(thread, &t->work); + } else if (!pending_async) { + binder_enqueue_work_ilocked(&t->work, &proc->todo); + } else { + binder_enqueue_work_ilocked(&t->work, &node->async_todo); + } + + if (!pending_async) + binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + + proc->outstanding_txns++; + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + + return 0; +} + +/** + * binder_get_node_refs_for_txn() - Get required refs on node for txn + * @node: struct binder_node for which to get refs + * @proc: returns @node->proc if valid + * @error: if no @proc then returns BR_DEAD_REPLY + * + * User-space normally keeps the node alive when creating a transaction + * since it has a reference to the target. The local strong ref keeps it + * alive if the sending process dies before the target process processes + * the transaction. If the source process is malicious or has a reference + * counting bug, relying on the local strong ref can fail. + * + * Since user-space can cause the local strong ref to go away, we also take + * a tmpref on the node to ensure it survives while we are constructing + * the transaction. We also need a tmpref on the proc while we are + * constructing the transaction, so we take that here as well. + * + * Return: The target_node with refs taken or NULL if no @node->proc is NULL. + * Also sets @proc if valid. If the @node->proc is NULL indicating that the + * target proc has died, @error is set to BR_DEAD_REPLY + */ +static struct binder_node *binder_get_node_refs_for_txn( + struct binder_node *node, + struct binder_proc **procp, + uint32_t *error) +{ + struct binder_node *target_node = NULL; + + binder_node_inner_lock(node); + if (node->proc) { + target_node = node; + binder_inc_node_nilocked(node, 1, 0, NULL); + binder_inc_node_tmpref_ilocked(node); + atomic_inc(&node->proc->tmp_ref); + *procp = node->proc; + } else + *error = BR_DEAD_REPLY; + binder_node_inner_unlock(node); + + return target_node; +} + static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply, @@ -1961,23 +2925,28 @@ static void binder_transaction(struct binder_proc *proc, { int ret; struct binder_transaction *t; + struct binder_work *w; struct binder_work *tcomplete; binder_size_t *offp, *off_end, *off_start; binder_size_t off_min; u8 *sg_bufp, *sg_buf_end; - struct binder_proc *target_proc; + struct binder_proc *target_proc = NULL; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; - struct list_head *target_list; - wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; - uint32_t return_error; + uint32_t return_error = 0; + uint32_t return_error_param = 0; + uint32_t return_error_line = 0; struct binder_buffer_object *last_fixup_obj = NULL; binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; + int t_debug_id = atomic_inc_return(&binder_last_id); + char *secctx = NULL; + u32 secctx_sz = 0; - e = binder_transaction_log_add(&context->transaction_log); + e = binder_transaction_log_add(&binder_transaction_log); + e->debug_id = t_debug_id; e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); e->from_proc = proc->pid; e->from_thread = thread->pid; @@ -1987,29 +2956,39 @@ static void binder_transaction(struct binder_proc *proc, e->context_name = proc->context->name; if (reply) { + binder_inner_proc_lock(proc); in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) { + binder_inner_proc_unlock(proc); binder_user_error("%d:%d got reply transaction with no transaction stack\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; goto err_empty_call_stack; } - binder_set_nice(in_reply_to->saved_priority); if (in_reply_to->to_thread != thread) { + spin_lock(&in_reply_to->lock); binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, in_reply_to->to_thread ? in_reply_to->to_thread->pid : 0); + spin_unlock(&in_reply_to->lock); + binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; in_reply_to = NULL; goto err_bad_call_stack; } thread->transaction_stack = in_reply_to->to_parent; - target_thread = in_reply_to->from; + binder_inner_proc_unlock(proc); + target_thread = binder_get_txn_from_and_acq_inner(in_reply_to); if (target_thread == NULL) { return_error = BR_DEAD_REPLY; + return_error_line = __LINE__; goto err_dead_binder; } if (target_thread->transaction_stack != in_reply_to) { @@ -2018,88 +2997,166 @@ static void binder_transaction(struct binder_proc *proc, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, in_reply_to->debug_id); + binder_inner_proc_unlock(target_thread->proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; in_reply_to = NULL; target_thread = NULL; goto err_dead_binder; } target_proc = target_thread->proc; + atomic_inc(&target_proc->tmp_ref); + binder_inner_proc_unlock(target_thread->proc); } else { if (tr->target.handle) { struct binder_ref *ref; - ref = binder_get_ref(proc, tr->target.handle, true); - if (ref == NULL) { + /* + * There must already be a strong ref + * on this node. If so, do a strong + * increment on the node to ensure it + * stays alive until the transaction is + * done. + */ + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, tr->target.handle, + true); + if (ref) { + target_node = binder_get_node_refs_for_txn( + ref->node, &target_proc, + &return_error); + } else { binder_user_error("%d:%d got transaction to invalid handle\n", - proc->pid, thread->pid); + proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - goto err_invalid_target_handle; } - target_node = ref->node; + binder_proc_unlock(proc); } else { + mutex_lock(&context->context_mgr_node_lock); target_node = context->binder_context_mgr_node; - if (target_node == NULL) { + if (target_node) + target_node = binder_get_node_refs_for_txn( + target_node, &target_proc, + &return_error); + else return_error = BR_DEAD_REPLY; - goto err_no_context_mgr_node; + mutex_unlock(&context->context_mgr_node_lock); + if (target_node && target_proc->pid == proc->pid) { + binder_user_error("%d:%d got transaction to context manager from process owning it\n", + proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; } } - e->to_node = target_node->debug_id; - target_proc = target_node->proc; - if (target_proc == NULL) { - return_error = BR_DEAD_REPLY; + if (!target_node) { + /* + * return_error is set above + */ + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_dead_binder; } - if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { + e->to_node = target_node->debug_id; + if (WARN_ON(proc == target_proc)) { + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; + } + if (security_binder_transaction(proc->tsk, + target_proc->tsk) < 0) { return_error = BR_FAILED_REPLY; + return_error_param = -EPERM; + return_error_line = __LINE__; goto err_invalid_target_handle; } + binder_inner_proc_lock(proc); + + w = list_first_entry_or_null(&thread->todo, + struct binder_work, entry); + if (!(tr->flags & TF_ONE_WAY) && w && + w->type == BINDER_WORK_TRANSACTION) { + /* + * Do not allow new outgoing transaction from a + * thread that has a transaction at the head of + * its todo list. Only need to check the head + * because binder_select_thread_ilocked picks a + * thread from proc->waiting_threads to enqueue + * the transaction, and nothing is queued to the + * todo list while the thread is on waiting_threads. + */ + binder_user_error("%d:%d new transaction not allowed when there is a transaction on thread todo\n", + proc->pid, thread->pid); + binder_inner_proc_unlock(proc); + return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; + goto err_bad_todo_list; + } + if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; if (tmp->to_thread != thread) { + spin_lock(&tmp->lock); binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? tmp->to_thread->pid : 0); + spin_unlock(&tmp->lock); + binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; goto err_bad_call_stack; } while (tmp) { - if (tmp->from && tmp->from->proc == target_proc) - target_thread = tmp->from; + struct binder_thread *from; + + spin_lock(&tmp->lock); + from = tmp->from; + if (from && from->proc == target_proc) { + atomic_inc(&from->tmp_ref); + target_thread = from; + spin_unlock(&tmp->lock); + break; + } + spin_unlock(&tmp->lock); tmp = tmp->from_parent; } } + binder_inner_proc_unlock(proc); } - if (target_thread) { + if (target_thread) e->to_thread = target_thread->pid; - target_list = &target_thread->todo; - target_wait = &target_thread->wait; - } else { - target_list = &target_proc->todo; - target_wait = &target_proc->wait; - } e->to_proc = target_proc->pid; /* TODO: reuse incoming transaction for reply */ - t = kzalloc_preempt_disabled(sizeof(*t)); + t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; goto err_alloc_t_failed; } binder_stats_created(BINDER_STAT_TRANSACTION); + spin_lock_init(&t->lock); - tcomplete = kzalloc_preempt_disabled(sizeof(*tcomplete)); + tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; goto err_alloc_tcomplete_failed; } binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); - t->debug_id = atomic_inc_return(&binder_last_id); - e->debug_id = t->debug_id; + t->debug_id = t_debug_id; if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, @@ -2129,47 +3186,100 @@ static void binder_transaction(struct binder_proc *proc, t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; - t->priority = task_nice(current); + if (!(t->flags & TF_ONE_WAY) && + binder_supported_policy(current->policy)) { + /* Inherit supported policies for synchronous transactions */ + t->priority.sched_policy = current->policy; + t->priority.prio = current->normal_prio; + } else { + /* Otherwise, fall back to the default priority */ + t->priority = target_proc->default_priority; + } + + if (target_node && target_node->txn_security_ctx) { + u32 secid; + size_t added_size; + + security_task_getsecid(proc->tsk, &secid); + ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); + if (ret) { + return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; + goto err_get_secctx_failed; + } + added_size = ALIGN(secctx_sz, sizeof(u64)); + extra_buffers_size += added_size; + if (extra_buffers_size < added_size) { + /* integer overflow of extra_buffers_size */ + return_error = BR_FAILED_REPLY; + return_error_param = EINVAL; + return_error_line = __LINE__; + goto err_bad_extra_size; + } + } trace_binder_transaction(reply, t, target_node); - t->buffer = binder_alloc_buf(target_proc, tr->data_size, + t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, tr->offsets_size, extra_buffers_size, - !reply && (t->flags & TF_ONE_WAY)); - if (t->buffer == NULL) { - return_error = BR_FAILED_REPLY; + !reply && (t->flags & TF_ONE_WAY), current->tgid); + if (IS_ERR(t->buffer)) { + /* + * -ESRCH indicates VMA cleared. The target is dying. + */ + return_error_param = PTR_ERR(t->buffer); + return_error = return_error_param == -ESRCH ? + BR_DEAD_REPLY : BR_FAILED_REPLY; + return_error_line = __LINE__; + t->buffer = NULL; goto err_binder_alloc_buf_failed; } - t->buffer->allow_user_free = 0; + if (secctx) { + size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) + + ALIGN(tr->offsets_size, sizeof(void *)) + + ALIGN(extra_buffers_size, sizeof(void *)) - + ALIGN(secctx_sz, sizeof(u64)); + char *kptr = t->buffer->data + buf_offset; + + t->security_ctx = (uintptr_t)kptr + + binder_alloc_get_user_buffer_offset(&target_proc->alloc); + memcpy(kptr, secctx, secctx_sz); + security_release_secctx(secctx, secctx_sz); + secctx = NULL; + } t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; trace_binder_transaction_alloc_buf(t->buffer); - if (target_node) - binder_inc_node(target_node, 1, 0, NULL); - off_start = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); offp = off_start; - if (copy_from_user_preempt_disabled(t->buffer->data, (const void __user *)(uintptr_t) + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EFAULT; + return_error_line = __LINE__; goto err_copy_data_failed; } - if (copy_from_user_preempt_disabled(offp, (const void __user *)(uintptr_t) + if (copy_from_user(offp, (const void __user *)(uintptr_t) tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EFAULT; + return_error_line = __LINE__; goto err_copy_data_failed; } if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) { @@ -2177,11 +3287,14 @@ static void binder_transaction(struct binder_proc *proc, proc->pid, thread->pid, (u64)extra_buffers_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } off_end = (void *)off_start + tr->offsets_size; sg_bufp = (u8 *)(PTR_ALIGN(off_end, sizeof(void *))); - sg_buf_end = sg_bufp + extra_buffers_size; + sg_buf_end = sg_bufp + extra_buffers_size - + ALIGN(secctx_sz, sizeof(u64)); off_min = 0; for (; offp < off_end; offp++) { struct binder_object_header *hdr; @@ -2193,6 +3306,8 @@ static void binder_transaction(struct binder_proc *proc, (u64)off_min, (u64)t->buffer->data_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } @@ -2207,6 +3322,8 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_binder(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -2218,6 +3335,8 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_handle(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -2229,6 +3348,8 @@ static void binder_transaction(struct binder_proc *proc, if (target_fd < 0) { return_error = BR_FAILED_REPLY; + return_error_param = target_fd; + return_error_line = __LINE__; goto err_translate_failed; } fp->pad_binder = 0; @@ -2245,6 +3366,8 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid parent offset or type\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_parent; } if (!binder_validate_fixup(t->buffer, off_start, @@ -2254,12 +3377,16 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_parent; } ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = parent; @@ -2275,20 +3402,24 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with too large buffer\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } - if (copy_from_user_preempt_disabled( - sg_bufp, - (const void __user *)(uintptr_t) - bp->buffer, bp->length)) { + if (copy_from_user(sg_bufp, + (const void __user *)(uintptr_t) + bp->buffer, bp->length)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); + return_error_param = -EFAULT; return_error = BR_FAILED_REPLY; + return_error_line = __LINE__; goto err_copy_data_failed; } /* Fixup buffer pointer to target proc address space */ bp->buffer = (uintptr_t)sg_bufp + - target_proc->user_buffer_offset; + binder_alloc_get_user_buffer_offset( + &target_proc->alloc); sg_bufp += ALIGN(bp->length, sizeof(u64)); ret = binder_fixup_parent(t, thread, bp, off_start, @@ -2297,6 +3428,8 @@ static void binder_transaction(struct binder_proc *proc, last_fixup_min_off); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = bp; @@ -2306,40 +3439,78 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid object type, %x\n", proc->pid, thread->pid, hdr->type); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_object_type; } } + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + t->work.type = BINDER_WORK_TRANSACTION; + if (reply) { + binder_enqueue_thread_work(thread, tcomplete); + binder_inner_proc_lock(target_proc); + if (target_thread->is_dead || target_proc->is_frozen) { + return_error = target_thread->is_dead ? + BR_DEAD_REPLY : BR_FROZEN_REPLY; + binder_inner_proc_unlock(target_proc); + goto err_dead_proc_or_thread; + } BUG_ON(t->buffer->async_transaction != 0); - binder_pop_transaction(target_thread, in_reply_to); + binder_pop_transaction_ilocked(target_thread, in_reply_to); + binder_enqueue_thread_work_ilocked(target_thread, &t->work); + target_proc->outstanding_txns++; + binder_inner_proc_unlock(target_proc); + wake_up_interruptible_sync(&target_thread->wait); + binder_restore_priority(current, in_reply_to->saved_priority); + binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); + binder_inner_proc_lock(proc); + /* + * Defer the TRANSACTION_COMPLETE, so we don't return to + * userspace immediately; this allows the target process to + * immediately start processing this transaction, reducing + * latency. We will then return the TRANSACTION_COMPLETE when + * the target replies (or there is an error). + */ + binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete); t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; + binder_inner_proc_unlock(proc); + return_error = binder_proc_transaction(t, + target_proc, target_thread); + if (return_error) { + binder_inner_proc_lock(proc); + binder_pop_transaction_ilocked(thread, t); + binder_inner_proc_unlock(proc); + goto err_dead_proc_or_thread; + } } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); - if (target_node->has_async_transaction) { - target_list = &target_node->async_todo; - target_wait = NULL; - } else - target_node->has_async_transaction = 1; - } - t->work.type = BINDER_WORK_TRANSACTION; - list_add_tail(&t->work.entry, target_list); - tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; - list_add_tail(&tcomplete->entry, &thread->todo); - if (target_wait) { - if (reply || !(t->flags & TF_ONE_WAY)) { - wake_up_interruptible_sync(target_wait); - } - else { - wake_up_interruptible(target_wait); - } - } + binder_enqueue_thread_work(thread, tcomplete); + return_error = binder_proc_transaction(t, target_proc, NULL); + if (return_error) + goto err_dead_proc_or_thread; + } + if (target_thread) + binder_thread_dec_tmpref(target_thread); + binder_proc_dec_tmpref(target_proc); + if (target_node) + binder_dec_node_tmpref(target_node); + /* + * write barrier to synchronize with initialization + * of log entry + */ + smp_wmb(); + WRITE_ONCE(e->debug_id_done, t_debug_id); return; +err_dead_proc_or_thread: + return_error_line = __LINE__; + binder_dequeue_work(proc, tcomplete); err_translate_failed: err_bad_object_type: err_bad_offset: @@ -2347,42 +3518,72 @@ err_bad_parent: err_copy_data_failed: trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); + if (target_node) + binder_dec_node_tmpref(target_node); + target_node = NULL; t->buffer->transaction = NULL; - binder_free_buf(target_proc, t->buffer); + binder_alloc_free_buf(&target_proc->alloc, t->buffer); err_binder_alloc_buf_failed: +err_bad_extra_size: + if (secctx) + security_release_secctx(secctx, secctx_sz); +err_get_secctx_failed: kfree(tcomplete); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); err_alloc_tcomplete_failed: kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: +err_bad_todo_list: err_bad_call_stack: err_empty_call_stack: err_dead_binder: err_invalid_target_handle: -err_no_context_mgr_node: + if (target_thread) + binder_thread_dec_tmpref(target_thread); + if (target_proc) + binder_proc_dec_tmpref(target_proc); + if (target_node) { + binder_dec_node(target_node, 1, 0); + binder_dec_node_tmpref(target_node); + } + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %lld-%lld\n", - proc->pid, thread->pid, return_error, - (u64)tr->data_size, (u64)tr->offsets_size); + "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n", + proc->pid, thread->pid, return_error, return_error_param, + (u64)tr->data_size, (u64)tr->offsets_size, + return_error_line); { struct binder_transaction_log_entry *fe; - fe = binder_transaction_log_add( - &context->transaction_log_failed); + e->return_error = return_error; + e->return_error_param = return_error_param; + e->return_error_line = return_error_line; + fe = binder_transaction_log_add(&binder_transaction_log_failed); *fe = *e; + /* + * write barrier to synchronize with initialization + * of log entry + */ + smp_wmb(); + WRITE_ONCE(e->debug_id_done, t_debug_id); + WRITE_ONCE(fe->debug_id_done, t_debug_id); } - BUG_ON(thread->return_error != BR_OK); + BUG_ON(thread->return_error.cmd != BR_OK); if (in_reply_to) { - thread->return_error = BR_TRANSACTION_COMPLETE; + binder_restore_priority(current, in_reply_to->saved_priority); + thread->return_error.cmd = BR_TRANSACTION_COMPLETE; + binder_enqueue_thread_work(thread, &thread->return_error.work); binder_send_failed_reply(in_reply_to, return_error); - } else - thread->return_error = return_error; + } else { + thread->return_error.cmd = return_error; + binder_enqueue_thread_work(thread, &thread->return_error.work); + } } -int binder_thread_write(struct binder_proc *proc, +static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed) @@ -2393,15 +3594,17 @@ int binder_thread_write(struct binder_proc *proc, void __user *ptr = buffer + *consumed; void __user *end = buffer + size; - while (ptr < end && thread->return_error == BR_OK) { - if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + while (ptr < end && thread->return_error.cmd == BR_OK) { + int ret; + + if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); trace_binder_command(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(context->binder_stats.bc)) { - context->binder_stats.bc[_IOC_NR(cmd)]++; - proc->stats.bc[_IOC_NR(cmd)]++; - thread->stats.bc[_IOC_NR(cmd)]++; + if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { + atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]); + atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]); + atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]); } switch (cmd) { case BC_INCREFS: @@ -2409,72 +3612,81 @@ int binder_thread_write(struct binder_proc *proc, case BC_RELEASE: case BC_DECREFS: { uint32_t target; - struct binder_ref *ref; const char *debug_string; + bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE; + bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; + struct binder_ref_data rdata; - if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) + if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; + ptr += sizeof(uint32_t); - if (target == 0 && context->binder_context_mgr_node && - (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { - ref = binder_get_ref_for_node(proc, - context->binder_context_mgr_node); - if (ref->desc != target) { - binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n", - proc->pid, thread->pid, - ref->desc); + ret = -1; + if (increment && !target) { + struct binder_node *ctx_mgr_node; + mutex_lock(&context->context_mgr_node_lock); + ctx_mgr_node = context->binder_context_mgr_node; + if (ctx_mgr_node) { + if (ctx_mgr_node->proc == proc) { + binder_user_error("%d:%d context manager tried to acquire desc 0\n", + proc->pid, thread->pid); + mutex_unlock(&context->context_mgr_node_lock); + return -EINVAL; + } + ret = binder_inc_ref_for_node( + proc, ctx_mgr_node, + strong, NULL, &rdata); } - } else - ref = binder_get_ref(proc, target, - cmd == BC_ACQUIRE || - cmd == BC_RELEASE); - if (ref == NULL) { - binder_user_error("%d:%d refcount change on invalid ref %d\n", - proc->pid, thread->pid, target); - break; + mutex_unlock(&context->context_mgr_node_lock); + } + if (ret) + ret = binder_update_ref_for_handle( + proc, target, increment, strong, + &rdata); + if (!ret && rdata.desc != target) { + binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n", + proc->pid, thread->pid, + target, rdata.desc); } switch (cmd) { case BC_INCREFS: debug_string = "IncRefs"; - binder_inc_ref(ref, 0, NULL); break; case BC_ACQUIRE: debug_string = "Acquire"; - binder_inc_ref(ref, 1, NULL); break; case BC_RELEASE: debug_string = "Release"; - binder_dec_ref(&ref, 1); break; case BC_DECREFS: default: debug_string = "DecRefs"; - binder_dec_ref(&ref, 0); break; } - if (ref == NULL) { - binder_debug(BINDER_DEBUG_USER_REFS, - "binder: %d:%d %s ref deleted", - proc->pid, thread->pid, debug_string); - } else { + if (ret) { + binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n", + proc->pid, thread->pid, debug_string, + strong, target, ret); + break; + } binder_debug(BINDER_DEBUG_USER_REFS, - "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, debug_string, - ref->debug_id, ref->desc, ref->strong, - ref->weak, ref->node->debug_id); - } - break; + "%d:%d %s ref %d desc %d s %d w %d\n", + proc->pid, thread->pid, debug_string, + rdata.debug_id, rdata.desc, rdata.strong, + rdata.weak); + break; } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { binder_uintptr_t node_ptr; binder_uintptr_t cookie; struct binder_node *node; + bool free_node; - if (get_user_preempt_disabled(node_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); @@ -2494,13 +3706,17 @@ int binder_thread_write(struct binder_proc *proc, "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", (u64)node_ptr, node->debug_id, (u64)cookie, (u64)node->cookie); + binder_put_node(node); break; } + binder_node_inner_lock(node); if (cmd == BC_ACQUIRE_DONE) { if (node->pending_strong_ref == 0) { binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", proc->pid, thread->pid, node->debug_id); + binder_node_inner_unlock(node); + binder_put_node(node); break; } node->pending_strong_ref = 0; @@ -2509,16 +3725,23 @@ int binder_thread_write(struct binder_proc *proc, binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", proc->pid, thread->pid, node->debug_id); + binder_node_inner_unlock(node); + binder_put_node(node); break; } node->pending_weak_ref = 0; } - binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); + free_node = binder_dec_node_nilocked(node, + cmd == BC_ACQUIRE_DONE, 0); + WARN_ON(free_node); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s node %d ls %d lw %d\n", + "%d:%d %s node %d ls %d lw %d tr %d\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node->debug_id, node->local_strong_refs, node->local_weak_refs); + node->debug_id, node->local_strong_refs, + node->local_weak_refs, node->tmp_refs); + binder_node_inner_unlock(node); + binder_put_node(node); break; } case BC_ATTEMPT_ACQUIRE: @@ -2532,19 +3755,24 @@ int binder_thread_write(struct binder_proc *proc, binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user_preempt_disabled(data_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - buffer = binder_buffer_lookup(proc, data_ptr); - if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", - proc->pid, thread->pid, (u64)data_ptr); - break; - } - if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", - proc->pid, thread->pid, (u64)data_ptr); + buffer = binder_alloc_prepare_to_free(&proc->alloc, + data_ptr); + if (IS_ERR_OR_NULL(buffer)) { + if (PTR_ERR(buffer) == -EPERM) { + binder_user_error( + "%d:%d BC_FREE_BUFFER u%016llx matched unreturned or currently freeing buffer\n", + proc->pid, thread->pid, + (u64)data_ptr); + } else { + binder_user_error( + "%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, + (u64)data_ptr); + } break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, @@ -2553,20 +3781,34 @@ int binder_thread_write(struct binder_proc *proc, buffer->debug_id, buffer->transaction ? "active" : "finished"); + binder_inner_proc_lock(proc); if (buffer->transaction) { buffer->transaction->buffer = NULL; buffer->transaction = NULL; } + binder_inner_proc_unlock(proc); if (buffer->async_transaction && buffer->target_node) { - BUG_ON(!buffer->target_node->has_async_transaction); - if (list_empty(&buffer->target_node->async_todo)) - buffer->target_node->has_async_transaction = 0; - else - list_move_tail(buffer->target_node->async_todo.next, &thread->todo); + struct binder_node *buf_node; + struct binder_work *w; + + buf_node = buffer->target_node; + binder_node_inner_lock(buf_node); + BUG_ON(!buf_node->has_async_transaction); + BUG_ON(buf_node->proc != proc); + w = binder_dequeue_work_head_ilocked( + &buf_node->async_todo); + if (!w) { + buf_node->has_async_transaction = false; + } else { + binder_enqueue_work_ilocked( + w, &proc->todo); + binder_wakeup_proc_ilocked(proc); + } + binder_node_inner_unlock(buf_node); } trace_binder_transaction_buffer_release(buffer); binder_transaction_buffer_release(proc, buffer, NULL); - binder_free_buf(proc, buffer); + binder_alloc_free_buf(&proc->alloc, buffer); break; } @@ -2574,8 +3816,7 @@ int binder_thread_write(struct binder_proc *proc, case BC_REPLY_SG: { struct binder_transaction_data_sg tr; - if (copy_from_user_preempt_disabled(&tr, ptr, - sizeof(tr))) + if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr.transaction_data, @@ -2586,7 +3827,7 @@ int binder_thread_write(struct binder_proc *proc, case BC_REPLY: { struct binder_transaction_data tr; - if (copy_from_user_preempt_disabled(&tr, ptr, sizeof(tr))) + if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr, @@ -2598,6 +3839,7 @@ int binder_thread_write(struct binder_proc *proc, binder_debug(BINDER_DEBUG_THREADS, "%d:%d BC_REGISTER_LOOPER\n", proc->pid, thread->pid); + binder_inner_proc_lock(proc); if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", @@ -2611,6 +3853,7 @@ int binder_thread_write(struct binder_proc *proc, proc->requested_threads_started++; } thread->looper |= BINDER_LOOPER_STATE_REGISTERED; + binder_inner_proc_unlock(proc); break; case BC_ENTER_LOOPER: binder_debug(BINDER_DEBUG_THREADS, @@ -2635,15 +3878,36 @@ int binder_thread_write(struct binder_proc *proc, uint32_t target; binder_uintptr_t cookie; struct binder_ref *ref; - struct binder_ref_death *death; + struct binder_ref_death *death = NULL; - if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) + if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - ref = binder_get_ref(proc, target, false); + if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { + /* + * Allocate memory for death notification + * before taking lock + */ + death = kzalloc(sizeof(*death), GFP_KERNEL); + if (death == NULL) { + WARN_ON(thread->return_error.cmd != + BR_OK); + thread->return_error.cmd = BR_ERROR; + binder_enqueue_thread_work( + thread, + &thread->return_error.work); + binder_debug( + BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); + break; + } + } + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, target, false); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", proc->pid, thread->pid, @@ -2651,6 +3915,8 @@ int binder_thread_write(struct binder_proc *proc, "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", target); + binder_proc_unlock(proc); + kfree(death); break; } @@ -2660,21 +3926,18 @@ int binder_thread_write(struct binder_proc *proc, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - (u64)cookie, ref->debug_id, ref->desc, - ref->strong, ref->weak, ref->node->debug_id); + (u64)cookie, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak, ref->node->debug_id); + binder_node_lock(ref->node); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", proc->pid, thread->pid); - break; - } - death = kzalloc_preempt_disabled(sizeof(*death)); - if (death == NULL) { - thread->return_error = BR_ERROR; - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); + kfree(death); break; } binder_stats_created(BINDER_STAT_DEATH); @@ -2683,17 +3946,19 @@ int binder_thread_write(struct binder_proc *proc, ref->death = death; if (ref->node->proc == NULL) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&ref->death->work.entry, &thread->todo); - } else { - list_add_tail(&ref->death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); - } + + binder_inner_proc_lock(proc); + binder_enqueue_work_ilocked( + &ref->death->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); } } else { if (ref->death == NULL) { binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", proc->pid, thread->pid); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); break; } death = ref->death; @@ -2702,34 +3967,52 @@ int binder_thread_write(struct binder_proc *proc, proc->pid, thread->pid, (u64)death->cookie, (u64)cookie); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); break; } ref->death = NULL; + binder_inner_proc_lock(proc); if (list_empty(&death->work.entry)) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); + if (thread->looper & + (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) + binder_enqueue_thread_work_ilocked( + thread, + &death->work); + else { + binder_enqueue_work_ilocked( + &death->work, + &proc->todo); + binder_wakeup_proc_ilocked( + proc); } } else { BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; } + binder_inner_proc_unlock(proc); } + binder_node_unlock(ref->node); + binder_proc_unlock(proc); } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(cookie); - list_for_each_entry(w, &proc->delivered_death, entry) { - struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + binder_inner_proc_lock(proc); + list_for_each_entry(w, &proc->delivered_death, + entry) { + struct binder_ref_death *tmp_death = + container_of(w, + struct binder_ref_death, + work); if (tmp_death->cookie == cookie) { death = tmp_death; @@ -2738,23 +4021,30 @@ int binder_thread_write(struct binder_proc *proc, } binder_debug(BINDER_DEBUG_DEAD_BINDER, "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n", - proc->pid, thread->pid, (u64)cookie, death); + proc->pid, thread->pid, (u64)cookie, + death); if (death == NULL) { binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", proc->pid, thread->pid, (u64)cookie); + binder_inner_proc_unlock(proc); break; } - - list_del_init(&death->work.entry); + binder_dequeue_work_ilocked(&death->work); if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); + if (thread->looper & + (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) + binder_enqueue_thread_work_ilocked( + thread, &death->work); + else { + binder_enqueue_work_ilocked( + &death->work, + &proc->todo); + binder_wakeup_proc_ilocked(proc); } } + binder_inner_proc_unlock(proc); } break; default: @@ -2771,24 +4061,74 @@ static void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t cmd) { trace_binder_return(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(proc->stats.br)) { - proc->context->binder_stats.br[_IOC_NR(cmd)]++; - proc->stats.br[_IOC_NR(cmd)]++; - thread->stats.br[_IOC_NR(cmd)]++; + if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { + atomic_inc(&binder_stats.br[_IOC_NR(cmd)]); + atomic_inc(&proc->stats.br[_IOC_NR(cmd)]); + atomic_inc(&thread->stats.br[_IOC_NR(cmd)]); } } -static int binder_has_proc_work(struct binder_proc *proc, - struct binder_thread *thread) +static int binder_put_node_cmd(struct binder_proc *proc, + struct binder_thread *thread, + void __user **ptrp, + binder_uintptr_t node_ptr, + binder_uintptr_t node_cookie, + int node_debug_id, + uint32_t cmd, const char *cmd_name) { - return !list_empty(&proc->todo) || - (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); + void __user *ptr = *ptrp; + + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + + if (put_user(node_ptr, (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + if (put_user(node_cookie, (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_USER_REFS, "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, node_debug_id, + (u64)node_ptr, (u64)node_cookie); + + *ptrp = ptr; + return 0; } -static int binder_has_thread_work(struct binder_thread *thread) +static int binder_wait_for_work(struct binder_thread *thread, + bool do_proc_work) { - return !list_empty(&thread->todo) || thread->return_error != BR_OK || - (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); + DEFINE_WAIT(wait); + struct binder_proc *proc = thread->proc; + int ret = 0; + + freezer_do_not_count(); + binder_inner_proc_lock(proc); + for (;;) { + prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE); + if (binder_has_work_ilocked(thread, do_proc_work)) + break; + if (do_proc_work) + list_add(&thread->waiting_thread_node, + &proc->waiting_threads); + binder_inner_proc_unlock(proc); + schedule(); + binder_inner_proc_lock(proc); + list_del_init(&thread->waiting_thread_node); + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + finish_wait(&thread->wait, &wait); + binder_inner_proc_unlock(proc); + freezer_count(); + + return ret; } static int binder_thread_read(struct binder_proc *proc, @@ -2804,43 +4144,21 @@ static int binder_thread_read(struct binder_proc *proc, int wait_for_proc_work; if (*consumed == 0) { - if (put_user_preempt_disabled(BR_NOOP, (uint32_t __user *)ptr)) + if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); } retry: - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo); - - if (thread->return_error != BR_OK && ptr < end) { - if (thread->return_error2 != BR_OK) { - if (put_user_preempt_disabled(thread->return_error2, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - binder_stat_br(proc, thread, thread->return_error2); - if (ptr == end) - goto done; - thread->return_error2 = BR_OK; - } - if (put_user_preempt_disabled(thread->return_error, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - binder_stat_br(proc, thread, thread->return_error); - thread->return_error = BR_OK; - goto done; - } - + binder_inner_proc_lock(proc); + wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); + binder_inner_proc_unlock(proc); thread->looper |= BINDER_LOOPER_STATE_WAITING; - if (wait_for_proc_work) - proc->ready_threads++; - - binder_unlock(proc->context, __func__); trace_binder_wait_for_work(wait_for_proc_work, !!thread->transaction_stack, - !list_empty(&thread->todo)); + !binder_worklist_empty(proc, &thread->todo)); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { @@ -2849,24 +4167,16 @@ retry: wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); } - binder_set_nice(proc->default_priority); - if (non_block) { - if (!binder_has_proc_work(proc, thread)) - ret = -EAGAIN; - } else - ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); - } else { - if (non_block) { - if (!binder_has_thread_work(thread)) - ret = -EAGAIN; - } else - ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); + binder_restore_priority(current, proc->default_priority); } - binder_lock(proc->context, __func__); + if (non_block) { + if (!binder_has_work(thread, wait_for_proc_work)) + ret = -EAGAIN; + } else { + ret = binder_wait_for_work(thread, wait_for_proc_work); + } - if (wait_for_proc_work) - proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; if (ret) @@ -2874,34 +4184,62 @@ retry: while (1) { uint32_t cmd; - struct binder_transaction_data tr; - struct binder_work *w; + struct binder_transaction_data_secctx tr; + struct binder_transaction_data *trd = &tr.transaction_data; + struct binder_work *w = NULL; + struct list_head *list = NULL; struct binder_transaction *t = NULL; + struct binder_thread *t_from; + size_t trsize = sizeof(*trd); + + binder_inner_proc_lock(proc); + if (!binder_worklist_empty_ilocked(&thread->todo)) + list = &thread->todo; + else if (!binder_worklist_empty_ilocked(&proc->todo) && + wait_for_proc_work) + list = &proc->todo; + else { + binder_inner_proc_unlock(proc); - if (!list_empty(&thread->todo)) { - w = list_first_entry(&thread->todo, struct binder_work, - entry); - } else if (!list_empty(&proc->todo) && wait_for_proc_work) { - w = list_first_entry(&proc->todo, struct binder_work, - entry); - } else { /* no data added */ - if (ptr - buffer == 4 && - !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) + if (ptr - buffer == 4 && !thread->looper_need_return) goto retry; break; } - if (end - ptr < sizeof(tr) + 4) + if (end - ptr < sizeof(tr) + 4) { + binder_inner_proc_unlock(proc); break; + } + w = binder_dequeue_work_head_ilocked(list); + if (binder_worklist_empty_ilocked(&thread->todo)) + thread->process_todo = false; switch (w->type) { case BINDER_WORK_TRANSACTION: { + binder_inner_proc_unlock(proc); t = container_of(w, struct binder_transaction, work); } break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + WARN_ON(e->cmd == BR_OK); + binder_inner_proc_unlock(proc); + if (put_user(e->cmd, (uint32_t __user *)ptr)) + return -EFAULT; + cmd = e->cmd; + e->cmd = BR_OK; + ptr += sizeof(uint32_t); + + binder_stat_br(proc, thread, e->cmd); + } break; case BINDER_WORK_TRANSACTION_COMPLETE: { + binder_inner_proc_unlock(proc); cmd = BR_TRANSACTION_COMPLETE; - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + kfree(w); + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); + if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); @@ -2909,113 +4247,132 @@ retry: binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, "%d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid); - - list_del(&w->entry); - kfree(w); - binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_NODE: { struct binder_node *node = container_of(w, struct binder_node, work); - uint32_t cmd = BR_NOOP; - const char *cmd_name; - int strong = node->internal_strong_refs || node->local_strong_refs; - int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; - - if (weak && !node->has_weak_ref) { - cmd = BR_INCREFS; - cmd_name = "BR_INCREFS"; + int strong, weak; + binder_uintptr_t node_ptr = node->ptr; + binder_uintptr_t node_cookie = node->cookie; + int node_debug_id = node->debug_id; + int has_weak_ref; + int has_strong_ref; + void __user *orig_ptr = ptr; + + BUG_ON(proc != node->proc); + strong = node->internal_strong_refs || + node->local_strong_refs; + weak = !hlist_empty(&node->refs) || + node->local_weak_refs || + node->tmp_refs || strong; + has_strong_ref = node->has_strong_ref; + has_weak_ref = node->has_weak_ref; + + if (weak && !has_weak_ref) { node->has_weak_ref = 1; node->pending_weak_ref = 1; node->local_weak_refs++; - } else if (strong && !node->has_strong_ref) { - cmd = BR_ACQUIRE; - cmd_name = "BR_ACQUIRE"; + } + if (strong && !has_strong_ref) { node->has_strong_ref = 1; node->pending_strong_ref = 1; node->local_strong_refs++; - } else if (!strong && node->has_strong_ref) { - cmd = BR_RELEASE; - cmd_name = "BR_RELEASE"; + } + if (!strong && has_strong_ref) node->has_strong_ref = 0; - } else if (!weak && node->has_weak_ref) { - cmd = BR_DECREFS; - cmd_name = "BR_DECREFS"; + if (!weak && has_weak_ref) node->has_weak_ref = 0; - } - if (cmd != BR_NOOP) { - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user_preempt_disabled(node->ptr, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - if (put_user_preempt_disabled(node->cookie, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - - binder_stat_br(proc, thread, cmd); - binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%016llx c%016llx\n", - proc->pid, thread->pid, cmd_name, - node->debug_id, - (u64)node->ptr, (u64)node->cookie); - } else { - list_del_init(&w->entry); - if (!weak && !strong) { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx deleted\n", - proc->pid, thread->pid, - node->debug_id, - (u64)node->ptr, - (u64)node->cookie); - rb_erase(&node->rb_node, &proc->nodes); - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); - } else { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx state unchanged\n", - proc->pid, thread->pid, - node->debug_id, - (u64)node->ptr, - (u64)node->cookie); - } - } + if (!weak && !strong) { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node_debug_id, + (u64)node_ptr, + (u64)node_cookie); + rb_erase(&node->rb_node, &proc->nodes); + binder_inner_proc_unlock(proc); + binder_node_lock(node); + /* + * Acquire the node lock before freeing the + * node to serialize with other threads that + * may have been holding the node lock while + * decrementing this node (avoids race where + * this thread frees while the other thread + * is unlocking the node after the final + * decrement) + */ + binder_node_unlock(node); + binder_free_node(node); + } else + binder_inner_proc_unlock(proc); + + if (weak && !has_weak_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_INCREFS, "BR_INCREFS"); + if (!ret && strong && !has_strong_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_ACQUIRE, "BR_ACQUIRE"); + if (!ret && !strong && has_strong_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_RELEASE, "BR_RELEASE"); + if (!ret && !weak && has_weak_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_DECREFS, "BR_DECREFS"); + if (orig_ptr == ptr) + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node_debug_id, + (u64)node_ptr, + (u64)node_cookie); + if (ret) + return ret; } break; case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { struct binder_ref_death *death; uint32_t cmd; + binder_uintptr_t cookie; death = container_of(w, struct binder_ref_death, work); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user_preempt_disabled(death->cookie, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - binder_stat_br(proc, thread, cmd); + cookie = death->cookie; + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - (u64)death->cookie); - + (u64)cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { - list_del(&w->entry); + binder_inner_proc_unlock(proc); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); - } else - list_move(&w->entry, &proc->delivered_death); + } else { + binder_enqueue_work_ilocked( + w, &proc->delivered_death); + binder_inner_proc_unlock(proc); + } + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user(cookie, + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + binder_stat_br(proc, thread, cmd); if (cmd == BR_DEAD_BINDER) goto done; /* DEAD_BINDER notifications can cause transactions */ } break; @@ -3027,50 +4384,69 @@ retry: BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; - - tr.target.ptr = target_node->ptr; - tr.cookie = target_node->cookie; - t->saved_priority = task_nice(current); - if (t->priority < target_node->min_priority && - !(t->flags & TF_ONE_WAY)) - binder_set_nice(t->priority); - else if (!(t->flags & TF_ONE_WAY) || - t->saved_priority > target_node->min_priority) - binder_set_nice(target_node->min_priority); + struct binder_priority node_prio; + + trd->target.ptr = target_node->ptr; + trd->cookie = target_node->cookie; + node_prio.sched_policy = target_node->sched_policy; + node_prio.prio = target_node->min_priority; + binder_transaction_priority(current, t, node_prio, + target_node->inherit_rt); cmd = BR_TRANSACTION; } else { - tr.target.ptr = 0; - tr.cookie = 0; + trd->target.ptr = 0; + trd->cookie = 0; cmd = BR_REPLY; } - tr.code = t->code; - tr.flags = t->flags; - tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); + trd->code = t->code; + trd->flags = t->flags; + trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid); - if (t->from) { - struct task_struct *sender = t->from->proc->tsk; + t_from = binder_get_txn_from(t); + if (t_from) { + struct task_struct *sender = t_from->proc->tsk; - tr.sender_pid = task_tgid_nr_ns(sender, - task_active_pid_ns(current)); + trd->sender_pid = + task_tgid_nr_ns(sender, + task_active_pid_ns(current)); } else { - tr.sender_pid = 0; + trd->sender_pid = 0; } - tr.data_size = t->buffer->data_size; - tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (binder_uintptr_t)( - (uintptr_t)t->buffer->data + - proc->user_buffer_offset); - tr.data.ptr.offsets = tr.data.ptr.buffer + + trd->data_size = t->buffer->data_size; + trd->offsets_size = t->buffer->offsets_size; + trd->data.ptr.buffer = (binder_uintptr_t) + ((uintptr_t)t->buffer->data + + binder_alloc_get_user_buffer_offset(&proc->alloc)); + trd->data.ptr.offsets = trd->data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); - if (put_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + tr.secctx = t->security_ctx; + if (t->security_ctx) { + cmd = BR_TRANSACTION_SEC_CTX; + trsize = sizeof(tr); + } + if (put_user(cmd, (uint32_t __user *)ptr)) { + if (t_from) + binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "put_user failed", + BR_FAILED_REPLY); + return -EFAULT; + } ptr += sizeof(uint32_t); - if (copy_to_user_preempt_disabled(ptr, &tr, sizeof(tr))) + if (copy_to_user(ptr, &tr, trsize)) { + if (t_from) + binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "copy_to_user failed", + BR_FAILED_REPLY); + return -EFAULT; - ptr += sizeof(tr); + } + ptr += trsize; trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); @@ -3078,22 +4454,25 @@ retry: "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : - "BR_REPLY", - t->debug_id, t->from ? t->from->proc->pid : 0, - t->from ? t->from->pid : 0, cmd, + (cmd == BR_TRANSACTION_SEC_CTX) ? + "BR_TRANSACTION_SEC_CTX" : "BR_REPLY", + t->debug_id, t_from ? t_from->proc->pid : 0, + t_from ? t_from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); + (u64)trd->data.ptr.buffer, + (u64)trd->data.ptr.offsets); - list_del(&t->work.entry); + if (t_from) + binder_thread_dec_tmpref(t_from); t->buffer->allow_user_free = 1; - if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { + if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) { + binder_inner_proc_lock(thread->proc); t->to_parent = thread->transaction_stack; t->to_thread = thread; thread->transaction_stack = t; + binder_inner_proc_unlock(thread->proc); } else { - t->buffer->transaction = NULL; - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); + binder_free_transaction(t); } break; } @@ -3101,45 +4480,56 @@ retry: done: *consumed = ptr - buffer; - if (proc->requested_threads + proc->ready_threads == 0 && + binder_inner_proc_lock(proc); + if (proc->requested_threads == 0 && + list_empty(&thread->proc->waiting_threads) && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) { proc->requested_threads++; + binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_THREADS, "%d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid); - if (put_user_preempt_disabled(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) + if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) return -EFAULT; binder_stat_br(proc, thread, BR_SPAWN_LOOPER); - } + } else + binder_inner_proc_unlock(proc); return 0; } -static void binder_release_work(struct list_head *list) +static void binder_release_work(struct binder_proc *proc, + struct list_head *list) { struct binder_work *w; + enum binder_work_type wtype; - while (!list_empty(list)) { - w = list_first_entry(list, struct binder_work, entry); - list_del_init(&w->entry); - switch (w->type) { + while (1) { + binder_inner_proc_lock(proc); + w = binder_dequeue_work_head_ilocked(list); + wtype = w ? w->type : 0; + binder_inner_proc_unlock(proc); + if (!w) + return; + + switch (wtype) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && - !(t->flags & TF_ONE_WAY)) { - binder_send_failed_reply(t, BR_DEAD_REPLY); - } else { - binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered transaction %d\n", - t->debug_id); - t->buffer->transaction = NULL; - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); - } + + binder_cleanup_transaction(t, "process died.", + BR_DEAD_REPLY); + } break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered TRANSACTION_ERROR: %u\n", + e->cmd); } break; case BINDER_WORK_TRANSACTION_COMPLETE: { binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, @@ -3158,16 +4548,19 @@ static void binder_release_work(struct list_head *list) kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; + case BINDER_WORK_NODE: + break; default: pr_err("unexpected work type, %d, not freed\n", - w->type); + wtype); break; } } } -static struct binder_thread *binder_get_thread(struct binder_proc *proc) +static struct binder_thread *binder_get_thread_ilocked( + struct binder_proc *proc, struct binder_thread *new_thread) { struct binder_thread *thread = NULL; struct rb_node *parent = NULL; @@ -3182,38 +4575,110 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) else if (current->pid > thread->pid) p = &(*p)->rb_right; else - break; + return thread; } - if (*p == NULL) { - thread = kzalloc_preempt_disabled(sizeof(*thread)); - if (thread == NULL) + if (!new_thread) + return NULL; + thread = new_thread; + binder_stats_created(BINDER_STAT_THREAD); + thread->proc = proc; + thread->pid = current->pid; + get_task_struct(current); + thread->task = current; + atomic_set(&thread->tmp_ref, 0); + init_waitqueue_head(&thread->wait); + INIT_LIST_HEAD(&thread->todo); + rb_link_node(&thread->rb_node, parent, p); + rb_insert_color(&thread->rb_node, &proc->threads); + thread->looper_need_return = true; + thread->return_error.work.type = BINDER_WORK_RETURN_ERROR; + thread->return_error.cmd = BR_OK; + thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; + thread->reply_error.cmd = BR_OK; + INIT_LIST_HEAD(&new_thread->waiting_thread_node); + return thread; +} + +static struct binder_thread *binder_get_thread(struct binder_proc *proc) +{ + struct binder_thread *thread; + struct binder_thread *new_thread; + + binder_inner_proc_lock(proc); + thread = binder_get_thread_ilocked(proc, NULL); + binder_inner_proc_unlock(proc); + if (!thread) { + new_thread = kzalloc(sizeof(*thread), GFP_KERNEL); + if (new_thread == NULL) return NULL; - binder_stats_created(BINDER_STAT_THREAD); - thread->proc = proc; - thread->pid = current->pid; - init_waitqueue_head(&thread->wait); - INIT_LIST_HEAD(&thread->todo); - rb_link_node(&thread->rb_node, parent, p); - rb_insert_color(&thread->rb_node, &proc->threads); - thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; - thread->return_error = BR_OK; - thread->return_error2 = BR_OK; + binder_inner_proc_lock(proc); + thread = binder_get_thread_ilocked(proc, new_thread); + binder_inner_proc_unlock(proc); + if (thread != new_thread) + kfree(new_thread); } return thread; } -static int binder_free_thread(struct binder_proc *proc, - struct binder_thread *thread) +static void binder_free_proc(struct binder_proc *proc) +{ + struct binder_device *device; + + BUG_ON(!list_empty(&proc->todo)); + BUG_ON(!list_empty(&proc->delivered_death)); + WARN_ON(proc->outstanding_txns); + device = container_of(proc->context, struct binder_device, context); + if (refcount_dec_and_test(&device->ref)) { + kfree(proc->context->name); + kfree(device); + } + binder_alloc_deferred_release(&proc->alloc); + put_task_struct(proc->tsk); + binder_stats_deleted(BINDER_STAT_PROC); + kfree(proc); +} + +static void binder_free_thread(struct binder_thread *thread) +{ + BUG_ON(!list_empty(&thread->todo)); + binder_stats_deleted(BINDER_STAT_THREAD); + binder_proc_dec_tmpref(thread->proc); + put_task_struct(thread->task); + kfree(thread); +} + +static int binder_thread_release(struct binder_proc *proc, + struct binder_thread *thread) { struct binder_transaction *t; struct binder_transaction *send_reply = NULL; int active_transactions = 0; + struct binder_transaction *last_t = NULL; + binder_inner_proc_lock(thread->proc); + /* + * take a ref on the proc so it survives + * after we remove this thread from proc->threads. + * The corresponding dec is when we actually + * free the thread in binder_free_thread() + */ + atomic_inc(&proc->tmp_ref); + /* + * take a ref on this thread to ensure it + * survives while we are releasing it + */ + atomic_inc(&thread->tmp_ref); rb_erase(&thread->rb_node, &proc->threads); t = thread->transaction_stack; - if (t && t->to_thread == thread) - send_reply = t; + if (t) { + spin_lock(&t->lock); + if (t->to_thread == thread) + send_reply = t; + } + thread->is_dead = true; + while (t) { + last_t = t; active_transactions++; binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "release %d:%d transaction %d %s, still active\n", @@ -3222,6 +4687,7 @@ static int binder_free_thread(struct binder_proc *proc, (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { + t->to_proc->outstanding_txns--; t->to_proc = NULL; t->to_thread = NULL; if (t->buffer) { @@ -3234,12 +4700,37 @@ static int binder_free_thread(struct binder_proc *proc, t = t->from_parent; } else BUG(); + spin_unlock(&last_t->lock); + if (t) + spin_lock(&t->lock); + } + + /* + * If this thread used poll, make sure we remove the waitqueue + * from any epoll data structures holding it with POLLFREE. + * waitqueue_active() is safe to use here because we're holding + * the inner lock. + */ + if ((thread->looper & BINDER_LOOPER_STATE_POLL) && + waitqueue_active(&thread->wait)) { + wake_up_poll(&thread->wait, POLLHUP | POLLFREE); } + + binder_inner_proc_unlock(thread->proc); + + /* + * This is needed to avoid races between wake_up_poll() above and + * and ep_remove_waitqueue() called for other reasons (eg the epoll file + * descriptor being closed); ep_remove_waitqueue() holds an RCU read + * lock, so we can be sure it's done after calling synchronize_rcu(). + */ + if (thread->looper & BINDER_LOOPER_STATE_POLL) + synchronize_rcu(); + if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); - binder_release_work(&thread->todo); - kfree(thread); - binder_stats_deleted(BINDER_STAT_THREAD); + binder_release_work(proc, &thread->todo); + binder_thread_dec_tmpref(thread); return active_transactions; } @@ -3248,30 +4739,23 @@ static unsigned int binder_poll(struct file *filp, { struct binder_proc *proc = filp->private_data; struct binder_thread *thread = NULL; - int wait_for_proc_work; - - binder_lock(proc->context, __func__); + bool wait_for_proc_work; thread = binder_get_thread(proc); + if (!thread) + return POLLERR; - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo) && thread->return_error == BR_OK; + binder_inner_proc_lock(thread->proc); + thread->looper |= BINDER_LOOPER_STATE_POLL; + wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); - binder_unlock(proc->context, __func__); + binder_inner_proc_unlock(thread->proc); + + poll_wait(filp, &thread->wait, wait); + + if (binder_has_work(thread, wait_for_proc_work)) + return POLLIN; - if (wait_for_proc_work) { - if (binder_has_proc_work(proc, thread)) - return POLLIN; - poll_wait(filp, &proc->wait, wait); - if (binder_has_proc_work(proc, thread)) - return POLLIN; - } else { - if (binder_has_thread_work(thread)) - return POLLIN; - poll_wait(filp, &thread->wait, wait); - if (binder_has_thread_work(thread)) - return POLLIN; - } return 0; } @@ -3289,7 +4773,7 @@ static int binder_ioctl_write_read(struct file *filp, ret = -EINVAL; goto out; } - if (copy_from_user_preempt_disabled(&bwr, ubuf, sizeof(bwr))) { + if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -3307,7 +4791,7 @@ static int binder_ioctl_write_read(struct file *filp, trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -3318,10 +4802,12 @@ static int binder_ioctl_write_read(struct file *filp, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); - if (!list_empty(&proc->todo)) - wake_up_interruptible(&proc->wait); + binder_inner_proc_lock(proc); + if (!binder_worklist_empty_ilocked(&proc->todo)) + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); if (ret < 0) { - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -3331,22 +4817,51 @@ static int binder_ioctl_write_read(struct file *filp, proc->pid, thread->pid, (u64)bwr.write_consumed, (u64)bwr.write_size, (u64)bwr.read_consumed, (u64)bwr.read_size); - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) { + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto out; } out: return ret; } - -static int binder_ioctl_set_ctx_mgr(struct file *filp) +/* +static int binder_ioctl_set_inherit_fifo_prio(struct file *filp) { int ret = 0; struct binder_proc *proc = filp->private_data; struct binder_context *context = proc->context; + kuid_t curr_euid = current_euid(); + mutex_lock(&context->context_mgr_node_lock); + + if (uid_valid(context->binder_context_mgr_uid)) { + if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) { + pr_err("BINDER_SET_INHERIT_FIFO_PRIO bad uid %d != %d\n", + from_kuid(&init_user_ns, curr_euid), + from_kuid(&init_user_ns, + context->binder_context_mgr_uid)); + ret = -EPERM; + goto out; + } + } + + context->inherit_fifo_prio = true; + + out: + mutex_unlock(&context->context_mgr_node_lock); + return ret; +} +*/ +static int binder_ioctl_set_ctx_mgr(struct file *filp, + struct flat_binder_object *fbo) +{ + int ret = 0; + struct binder_proc *proc = filp->private_data; + struct binder_context *context = proc->context; + struct binder_node *new_node; kuid_t curr_euid = current_euid(); + mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node) { pr_err("BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; @@ -3367,24 +4882,158 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) } else { context->binder_context_mgr_uid = curr_euid; } - context->binder_context_mgr_node = binder_new_node(proc, 0, 0); - if (!context->binder_context_mgr_node) { + new_node = binder_new_node(proc, fbo); + if (!new_node) { ret = -ENOMEM; goto out; } - context->binder_context_mgr_node->local_weak_refs++; - context->binder_context_mgr_node->local_strong_refs++; - context->binder_context_mgr_node->has_strong_ref = 1; - context->binder_context_mgr_node->has_weak_ref = 1; + binder_node_lock(new_node); + new_node->local_weak_refs++; + new_node->local_strong_refs++; + new_node->has_strong_ref = 1; + new_node->has_weak_ref = 1; + context->binder_context_mgr_node = new_node; + binder_node_unlock(new_node); + binder_put_node(new_node); out: + mutex_unlock(&context->context_mgr_node_lock); + return ret; +} + +static int binder_ioctl_get_node_info_for_ref(struct binder_proc *proc, + struct binder_node_info_for_ref *info) +{ + struct binder_node *node; + struct binder_context *context = proc->context; + __u32 handle = info->handle; + + if (info->strong_count || info->weak_count || info->reserved1 || + info->reserved2 || info->reserved3) { + binder_user_error("%d BINDER_GET_NODE_INFO_FOR_REF: only handle may be non-zero.", + proc->pid); + return -EINVAL; + } + + /* This ioctl may only be used by the context manager */ + mutex_lock(&context->context_mgr_node_lock); + if (!context->binder_context_mgr_node || + context->binder_context_mgr_node->proc != proc) { + mutex_unlock(&context->context_mgr_node_lock); + return -EPERM; + } + mutex_unlock(&context->context_mgr_node_lock); + + node = binder_get_node_from_ref(proc, handle, true, NULL); + if (!node) + return -EINVAL; + + info->strong_count = node->local_strong_refs + + node->internal_strong_refs; + info->weak_count = node->local_weak_refs; + + binder_put_node(node); + + return 0; +} + +static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, + struct binder_node_debug_info *info) { + struct rb_node *n; + binder_uintptr_t ptr = info->ptr; + + memset(info, 0, sizeof(*info)); + + binder_inner_proc_lock(proc); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { + struct binder_node *node = rb_entry(n, struct binder_node, + rb_node); + if (node->ptr > ptr) { + info->ptr = node->ptr; + info->cookie = node->cookie; + info->has_strong_ref = node->has_strong_ref; + info->has_weak_ref = node->has_weak_ref; + break; + } + } + binder_inner_proc_unlock(proc); + + return 0; +} + +static int binder_ioctl_freeze(struct binder_freeze_info *info, + struct binder_proc *target_proc) +{ + int ret = 0; + + if (!info->enable) { + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + return 0; + } + + /* + * Freezing the target. Prevent new transactions by + * setting frozen state. If timeout specified, wait + * for transactions to drain. + */ + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = true; + binder_inner_proc_unlock(target_proc); + + if (info->timeout_ms > 0) + ret = wait_event_interruptible_timeout( + target_proc->freeze_wait, + (!target_proc->outstanding_txns), + msecs_to_jiffies(info->timeout_ms)); + + if (!ret && target_proc->outstanding_txns) + ret = -EAGAIN; + + if (ret < 0) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + } + return ret; } +static int binder_ioctl_get_freezer_info( + struct binder_frozen_status_info *info) +{ + struct binder_proc *target_proc; + bool found = false; + + info->sync_recv = 0; + info->async_recv = 0; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info->pid) { + found = true; + binder_inner_proc_lock(target_proc); + info->sync_recv |= target_proc->sync_recv; + info->async_recv |= target_proc->async_recv; + binder_inner_proc_unlock(target_proc); + } + } + mutex_unlock(&binder_procs_lock); + + if (!found) + return -EINVAL; + + return 0; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; struct binder_proc *proc = filp->private_data; - struct binder_context *context = proc->context; struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; @@ -3392,51 +5041,193 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + binder_selftest_alloc(&proc->alloc); + trace_binder_ioctl(cmd, arg); ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) goto err_unlocked; - binder_lock(context, __func__); thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; goto err; } - switch (cmd) { - case BINDER_WRITE_READ: - ret = binder_ioctl_write_read(filp, cmd, arg, thread); - if (ret) + switch (cmd) { + case BINDER_WRITE_READ: + ret = binder_ioctl_write_read(filp, cmd, arg, thread); + if (ret) + goto err; + break; + case BINDER_SET_MAX_THREADS: { + int max_threads; + + if (copy_from_user(&max_threads, ubuf, + sizeof(max_threads))) { + ret = -EINVAL; + goto err; + } + binder_inner_proc_lock(proc); + proc->max_threads = max_threads; + binder_inner_proc_unlock(proc); + break; + } + case BINDER_SET_CONTEXT_MGR_EXT: { + struct flat_binder_object fbo; + + if (copy_from_user(&fbo, ubuf, sizeof(fbo))) { + ret = -EINVAL; + goto err; + } + ret = binder_ioctl_set_ctx_mgr(filp, &fbo); + if (ret) + goto err; + break; + } + case BINDER_SET_CONTEXT_MGR: + ret = binder_ioctl_set_ctx_mgr(filp, NULL); + if (ret) + goto err; + break; + /*case BINDER_SET_INHERIT_FIFO_PRIO: + ret = binder_ioctl_set_inherit_fifo_prio(filp); + if (ret) + goto err; + break;*/ + + case BINDER_THREAD_EXIT: + binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", + proc->pid, thread->pid); + binder_thread_release(proc, thread); + thread = NULL; + break; + case BINDER_VERSION: { + struct binder_version __user *ver = ubuf; + + if (size != sizeof(struct binder_version)) { + ret = -EINVAL; + goto err; + } + if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, + &ver->protocol_version)) { + ret = -EINVAL; + goto err; + } + break; + } + case BINDER_GET_NODE_INFO_FOR_REF: { + struct binder_node_info_for_ref info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_info_for_ref(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + break; + } + case BINDER_GET_NODE_DEBUG_INFO: { + struct binder_node_debug_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_debug_info(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; goto err; + } break; - case BINDER_SET_MAX_THREADS: - if (copy_from_user_preempt_disabled(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { + } + case BINDER_FREEZE: { + struct binder_freeze_info info; + struct binder_proc **target_procs = NULL, *target_proc; + int target_procs_count = 0, i = 0; + + ret = 0; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info.pid) + target_procs_count++; + } + + if (target_procs_count == 0) { + mutex_unlock(&binder_procs_lock); ret = -EINVAL; goto err; } - break; - case BINDER_SET_CONTEXT_MGR: - ret = binder_ioctl_set_ctx_mgr(filp); - if (ret) + + target_procs = kmalloc(sizeof(struct binder_proc *) * + target_procs_count, + GFP_KERNEL); + + if (!target_procs) { + mutex_unlock(&binder_procs_lock); + ret = -ENOMEM; + goto err; + } + + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid != info.pid) + continue; + + binder_inner_proc_lock(target_proc); + atomic_inc(&proc->tmp_ref); + binder_inner_proc_unlock(target_proc); + + target_procs[i++] = target_proc; + } + mutex_unlock(&binder_procs_lock); + + for (i = 0; i < target_procs_count; i++) { + if (ret >= 0) + ret = binder_ioctl_freeze(&info, + target_procs[i]); + + binder_proc_dec_tmpref(target_procs[i]); + } + + kfree(target_procs); + + if (ret < 0) goto err; break; - case BINDER_THREAD_EXIT: - binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", - proc->pid, thread->pid); - binder_free_thread(proc, thread); - thread = NULL; - break; - case BINDER_VERSION: { - struct binder_version __user *ver = ubuf; + } + case BINDER_GET_FROZEN_INFO: { + struct binder_frozen_status_info info; - if (size != sizeof(struct binder_version)) { - ret = -EINVAL; + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; goto err; } - if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION, &ver->protocol_version)) { - ret = -EINVAL; + + ret = binder_ioctl_get_freezer_info(&info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; goto err; } break; @@ -3448,10 +5239,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = 0; err: if (thread) - thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - binder_unlock(context, __func__); + thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret && ret != -ERESTARTSYS) + if (ret && ret != -EINTR) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); err_unlocked: trace_binder_ioctl_done(ret); @@ -3478,8 +5268,7 @@ static void binder_vma_close(struct vm_area_struct *vma) proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); - proc->vma = NULL; - proc->vma_vm_mm = NULL; + binder_alloc_vma_close(&proc->alloc); binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } @@ -3488,7 +5277,7 @@ static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -static struct vm_operations_struct binder_vm_ops = { +static const struct vm_operations_struct binder_vm_ops = { .open = binder_vma_open, .close = binder_vma_close, .fault = binder_vm_fault, @@ -3497,21 +5286,15 @@ static struct vm_operations_struct binder_vm_ops = { static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; - - struct vm_struct *area; struct binder_proc *proc = filp->private_data; const char *failure_string; - struct binder_buffer *buffer; if (proc->tsk != current->group_leader) return -EINVAL; - if ((vma->vm_end - vma->vm_start) > SZ_4M) - vma->vm_end = vma->vm_start + SZ_4M; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", - proc->pid, vma->vm_start, vma->vm_end, + "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", + __func__, proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); @@ -3520,95 +5303,22 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) failure_string = "bad vm_flags"; goto err_bad_arg; } - vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; - - mutex_lock(&proc->context->binder_mmap_lock); - if (proc->buffer) { - ret = -EBUSY; - failure_string = "already mapped"; - goto err_already_mapped; - } - - area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); - if (area == NULL) { - ret = -ENOMEM; - failure_string = "get_vm_area"; - goto err_get_vm_area_failed; - } - proc->buffer = area->addr; - proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; - mutex_unlock(&proc->context->binder_mmap_lock); - -#ifdef CONFIG_CPU_CACHE_VIPT - if (cache_is_vipt_aliasing()) { - while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { - pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); - vma->vm_start += PAGE_SIZE; - } - } -#endif - if (vma->vm_end - vma->vm_start < BINDER_MIN_ALLOC) { - ret = -EINVAL; - failure_string = "VMA size < BINDER_MIN_ALLOC"; - goto err_vma_too_small; - } - proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); - if (proc->pages == NULL) { - ret = -ENOMEM; - failure_string = "alloc page array"; - goto err_alloc_pages_failed; - } - proc->buffer_size = vma->vm_end - vma->vm_start; + vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP; + vma->vm_flags &= ~VM_MAYWRITE; vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - failure_string = "alloc buffer struct"; - goto err_alloc_buf_struct_failed; - } - - /* binder_update_page_range assumes preemption is disabled */ - preempt_disable(); - ret = __binder_update_page_range(proc, 1, proc->buffer, - proc->buffer + BINDER_MIN_ALLOC, vma); - preempt_enable_no_resched(); - if (ret) { - ret = -ENOMEM; - failure_string = "alloc small buf"; - goto err_alloc_small_buf_failed; - } - buffer->data = proc->buffer; - list_add(&buffer->entry, &proc->buffers); - buffer->free = 1; - binder_insert_free_buffer(proc, buffer); - proc->free_async_space = proc->buffer_size / 2; - barrier(); + ret = binder_alloc_mmap_handler(&proc->alloc, vma); + if (ret) + return ret; + mutex_lock(&proc->files_lock); proc->files = get_files_struct(current); - proc->vma = vma; - proc->vma_vm_mm = vma->vm_mm; - - /*pr_info("binder_mmap: %d %lx-%lx maps %pK\n", - proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ + mutex_unlock(&proc->files_lock); return 0; -err_alloc_small_buf_failed: - kfree(buffer); -err_alloc_buf_struct_failed: - kfree(proc->pages); - proc->pages = NULL; -err_alloc_pages_failed: -err_vma_too_small: - mutex_lock(&proc->context->binder_mmap_lock); - vfree(proc->buffer); - proc->buffer = NULL; -err_get_vm_area_failed: -err_already_mapped: - mutex_unlock(&proc->context->binder_mmap_lock); err_bad_arg: - pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -3617,32 +5327,54 @@ static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; struct binder_device *binder_dev; + struct binderfs_info *info; + struct dentry *binder_binderfs_dir_entry_proc = NULL; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; + spin_lock_init(&proc->inner_lock); + spin_lock_init(&proc->outer_lock); + atomic_set(&proc->tmp_ref, 0); get_task_struct(current->group_leader); proc->tsk = current->group_leader; + mutex_init(&proc->files_lock); INIT_LIST_HEAD(&proc->todo); - init_waitqueue_head(&proc->wait); - proc->default_priority = task_nice(current); - INIT_LIST_HEAD(&proc->buffers); - binder_dev = container_of(filp->private_data, struct binder_device, - miscdev); - proc->context = &binder_dev->context; + init_waitqueue_head(&proc->freeze_wait); + if (binder_supported_policy(current->policy)) { + proc->default_priority.sched_policy = current->policy; + proc->default_priority.prio = current->normal_prio; + } else { + proc->default_priority.sched_policy = SCHED_NORMAL; + proc->default_priority.prio = NICE_TO_PRIO(0); + } - binder_lock(proc->context, __func__); + //proc->default_priority = task_nice(current); + /* binderfs stashes devices in i_private */ + if (is_binderfs_device(nodp)) { + binder_dev = nodp->i_private; + info = nodp->i_sb->s_fs_info; + binder_binderfs_dir_entry_proc = info->proc_log_dir; + } else { + binder_dev = container_of(filp->private_data, + struct binder_device, miscdev); + } + refcount_inc(&binder_dev->ref); + proc->context = &binder_dev->context; + binder_alloc_init(&proc->alloc); binder_stats_created(BINDER_STAT_PROC); - hlist_add_head(&proc->proc_node, &proc->context->binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); + INIT_LIST_HEAD(&proc->waiting_threads); filp->private_data = proc; - binder_unlock(proc->context, __func__); + mutex_lock(&binder_procs_lock); + hlist_add_head(&proc->proc_node, &binder_procs); + mutex_unlock(&binder_procs_lock); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; @@ -3655,10 +5387,39 @@ static int binder_open(struct inode *nodp, struct file *filp) * anyway print all contexts that a given PID has, so this * is not a problem. */ - proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + proc->debugfs_entry = debugfs_create_file(strbuf, 0444, binder_debugfs_dir_entry_proc, (void *)(unsigned long)proc->pid, - &binder_proc_fops); + &proc_fops); + } + + if (binder_binderfs_dir_entry_proc) { + char strbuf[11]; + struct dentry *binderfs_entry; + + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); + /* + * Similar to debugfs, the process specific log file is shared + * between contexts. If the file has already been created for a + * process, the following binderfs_create_file() call will + * fail with error code EEXIST if another context of the same + * process invoked binder_open(). This is ok since same as + * debugfs, the log file will contain information on all + * contexts of a given PID. + */ + binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc, + strbuf, &proc_fops, (void *)(unsigned long)proc->pid); + if (!IS_ERR(binderfs_entry)) { + proc->binderfs_entry = binderfs_entry; + } else { + int error; + + error = PTR_ERR(binderfs_entry); + if (error != -EEXIST) { + pr_warn("Unable to create file %s in binderfs (error %d)\n", + strbuf, error); + } + } } return 0; @@ -3678,16 +5439,17 @@ static void binder_deferred_flush(struct binder_proc *proc) struct rb_node *n; int wake_count = 0; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); - thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; + thread->looper_need_return = true; if (thread->looper & BINDER_LOOPER_STATE_WAITING) { wake_up_interruptible(&thread->wait); wake_count++; } } - wake_up_interruptible_all(&proc->wait); + binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_flush: %d woke %d threads\n", proc->pid, @@ -3699,6 +5461,12 @@ static int binder_release(struct inode *nodp, struct file *filp) struct binder_proc *proc = filp->private_data; debugfs_remove(proc->debugfs_entry); + + if (proc->binderfs_entry) { + binderfs_remove_file(proc->binderfs_entry); + proc->binderfs_entry = NULL; + } + binder_defer_work(proc, BINDER_DEFERRED_RELEASE); return 0; @@ -3707,15 +5475,22 @@ static int binder_release(struct inode *nodp, struct file *filp) static int binder_node_release(struct binder_node *node, int refs) { struct binder_ref *ref; - struct binder_context *context = node->proc->context; int death = 0; + struct binder_proc *proc = node->proc; - list_del_init(&node->work.entry); - binder_release_work(&node->async_todo); + binder_release_work(proc, &node->async_todo); - if (hlist_empty(&node->refs)) { - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); + binder_node_lock(node); + binder_inner_proc_lock(proc); + binder_dequeue_work_ilocked(&node->work); + /* + * The caller must have taken a temporary ref on the node, + */ + BUG_ON(!node->tmp_refs); + if (hlist_empty(&node->refs) && node->tmp_refs == 1) { + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + binder_free_node(node); return refs; } @@ -3723,46 +5498,59 @@ static int binder_node_release(struct binder_node *node, int refs) node->proc = NULL; node->local_strong_refs = 0; node->local_weak_refs = 0; - hlist_add_head(&node->dead_node, &context->binder_dead_nodes); + binder_inner_proc_unlock(proc); + + spin_lock(&binder_dead_nodes_lock); + hlist_add_head(&node->dead_node, &binder_dead_nodes); + spin_unlock(&binder_dead_nodes_lock); hlist_for_each_entry(ref, &node->refs, node_entry) { refs++; - - if (!ref->death) + /* + * Need the node lock to synchronize + * with new notification requests and the + * inner lock to synchronize with queued + * death notifications. + */ + binder_inner_proc_lock(ref->proc); + if (!ref->death) { + binder_inner_proc_unlock(ref->proc); continue; + } death++; - if (list_empty(&ref->death->work.entry)) { - ref->death->work.type = BINDER_WORK_DEAD_BINDER; - list_add_tail(&ref->death->work.entry, - &ref->proc->todo); - wake_up_interruptible(&ref->proc->wait); - } else - BUG(); + BUG_ON(!list_empty(&ref->death->work.entry)); + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + binder_enqueue_work_ilocked(&ref->death->work, + &ref->proc->todo); + binder_wakeup_proc_ilocked(ref->proc); + binder_inner_proc_unlock(ref->proc); } binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); + binder_node_unlock(node); + binder_put_node(node); return refs; } static void binder_deferred_release(struct binder_proc *proc) { - struct binder_transaction *t; struct binder_context *context = proc->context; struct rb_node *n; - struct binder_buffer *buffer; - int threads, nodes, incoming_refs, outgoing_refs, buffers, - active_transactions, page_count; - BUG_ON(proc->vma); + int threads, nodes, incoming_refs, outgoing_refs, active_transactions; + BUG_ON(proc->files); + mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); + mutex_unlock(&binder_procs_lock); + mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node && context->binder_context_mgr_node->proc == proc) { binder_debug(BINDER_DEBUG_DEAD_BINDER, @@ -3770,15 +5558,28 @@ static void binder_deferred_release(struct binder_proc *proc) __func__, proc->pid); context->binder_context_mgr_node = NULL; } + mutex_unlock(&context->context_mgr_node_lock); + binder_inner_proc_lock(proc); + /* + * Make sure proc stays alive after we + * remove all the threads + */ + atomic_inc(&proc->tmp_ref); + proc->is_dead = true; + proc->is_frozen = false; + proc->sync_recv = false; + proc->async_recv = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { struct binder_thread *thread; thread = rb_entry(n, struct binder_thread, rb_node); + binder_inner_proc_unlock(proc); threads++; - active_transactions += binder_free_thread(proc, thread); + active_transactions += binder_thread_release(proc, thread); + binder_inner_proc_lock(proc); } nodes = 0; @@ -3788,104 +5589,56 @@ static void binder_deferred_release(struct binder_proc *proc) node = rb_entry(n, struct binder_node, rb_node); nodes++; + /* + * take a temporary ref on the node before + * calling binder_node_release() which will either + * kfree() the node or call binder_put_node() + */ + binder_inc_node_tmpref_ilocked(node); rb_erase(&node->rb_node, &proc->nodes); - incoming_refs = binder_node_release(node, - incoming_refs); + binder_inner_proc_unlock(proc); + incoming_refs = binder_node_release(node, incoming_refs); + binder_inner_proc_lock(proc); } + binder_inner_proc_unlock(proc); outgoing_refs = 0; + binder_proc_lock(proc); while ((n = rb_first(&proc->refs_by_desc))) { struct binder_ref *ref; ref = rb_entry(n, struct binder_ref, rb_node_desc); outgoing_refs++; - binder_delete_ref(ref); - } - - binder_release_work(&proc->todo); - binder_release_work(&proc->delivered_death); - - buffers = 0; - while ((n = rb_first(&proc->allocated_buffers))) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - - t = buffer->transaction; - if (t) { - t->buffer = NULL; - buffer->transaction = NULL; - pr_err("release proc %d, transaction %d, not freed\n", - proc->pid, t->debug_id); - /*BUG();*/ - } - - binder_free_buf(proc, buffer); - buffers++; + binder_cleanup_ref_olocked(ref); + binder_proc_unlock(proc); + binder_free_ref(ref); + binder_proc_lock(proc); } + binder_proc_unlock(proc); - binder_stats_deleted(BINDER_STAT_PROC); - - while (!list_empty(&proc->buffers)) { - buffer = list_first_entry(&proc->buffers, - struct binder_buffer, entry); - WARN_ON(!buffer->free); - - list_del(&buffer->entry); - WARN_ON_ONCE(!list_empty(&proc->buffers)); - kfree(buffer); - } - - page_count = 0; - if (proc->pages) { - int i; - - for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { - void *page_addr; - - if (!proc->pages[i]) - continue; - - page_addr = proc->buffer + i * PAGE_SIZE; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%s: %d: page %d at %pK not freed\n", - __func__, proc->pid, i, page_addr); - unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); - __free_page(proc->pages[i]); - page_count++; - } - kfree(proc->pages); - vfree(proc->buffer); - } - - put_task_struct(proc->tsk); + binder_release_work(proc, &proc->todo); + binder_release_work(proc, &proc->delivered_death); binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", + "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", __func__, proc->pid, threads, nodes, incoming_refs, - outgoing_refs, active_transactions, buffers, page_count); + outgoing_refs, active_transactions); - kfree(proc); + binder_proc_dec_tmpref(proc); } static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; struct files_struct *files; - struct binder_context *context = - container_of(work, struct binder_context, deferred_work); int defer; do { - trace_binder_lock(__func__); - mutex_lock(&context->binder_main_lock); - trace_binder_locked(__func__); - - mutex_lock(&context->binder_deferred_lock); - preempt_disable(); - if (!hlist_empty(&context->binder_deferred_list)) { - proc = hlist_entry(context->binder_deferred_list.first, - struct binder_proc, - deferred_work_node); + mutex_lock(&binder_deferred_lock); + if (!hlist_empty(&binder_deferred_list)) { + proc = hlist_entry(binder_deferred_list.first, + struct binder_proc, deferred_work_node); hlist_del_init(&proc->deferred_work_node); defer = proc->deferred_work; proc->deferred_work = 0; @@ -3893,13 +5646,15 @@ static void binder_deferred_func(struct work_struct *work) proc = NULL; defer = 0; } - mutex_unlock(&context->binder_deferred_lock); + mutex_unlock(&binder_deferred_lock); files = NULL; if (defer & BINDER_DEFERRED_PUT_FILES) { + mutex_lock(&proc->files_lock); files = proc->files; if (files) proc->files = NULL; + mutex_unlock(&proc->files_lock); } if (defer & BINDER_DEFERRED_FLUSH) @@ -3908,63 +5663,71 @@ static void binder_deferred_func(struct work_struct *work) if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - trace_binder_unlock(__func__); - mutex_unlock(&context->binder_main_lock); - preempt_enable_no_resched(); if (files) put_files_struct(files); } while (proc); } +static DECLARE_WORK(binder_deferred_work, binder_deferred_func); static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) { - mutex_lock(&proc->context->binder_deferred_lock); + mutex_lock(&binder_deferred_lock); proc->deferred_work |= defer; if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, - &proc->context->binder_deferred_list); - queue_work(proc->context->binder_deferred_workqueue, - &proc->context->deferred_work); + &binder_deferred_list); + queue_work(binder_deferred_workqueue, &binder_deferred_work); } - mutex_unlock(&proc->context->binder_deferred_lock); + mutex_unlock(&binder_deferred_lock); } -static void print_binder_transaction(struct seq_file *m, const char *prefix, - struct binder_transaction *t) +static void print_binder_transaction_ilocked(struct seq_file *m, + struct binder_proc *proc, + const char *prefix, + struct binder_transaction *t) { + struct binder_proc *to_proc; + struct binder_buffer *buffer = t->buffer; + + spin_lock(&t->lock); + to_proc = t->to_proc; seq_printf(m, - "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d", + "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %d:%d r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, - t->to_proc ? t->to_proc->pid : 0, + to_proc ? to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority, t->need_reply); - if (t->buffer == NULL) { + t->code, t->flags, t->priority.sched_policy, + t->priority.prio, t->need_reply); + spin_unlock(&t->lock); + + if (proc != to_proc) { + /* + * Can only safely deref buffer if we are holding the + * correct proc inner lock for this node + */ + seq_puts(m, "\n"); + return; + } + + if (buffer == NULL) { seq_puts(m, " buffer free\n"); return; } - if (t->buffer->target_node) - seq_printf(m, " node %d", - t->buffer->target_node->debug_id); + if (buffer->target_node) + seq_printf(m, " node %d", buffer->target_node->debug_id); seq_printf(m, " size %zd:%zd data %pK\n", - t->buffer->data_size, t->buffer->offsets_size, - t->buffer->data); -} - -static void print_binder_buffer(struct seq_file *m, const char *prefix, - struct binder_buffer *buffer) -{ - seq_printf(m, "%s %d: %pK size %zd:%zd %s\n", - prefix, buffer->debug_id, buffer->data, buffer->data_size, buffer->offsets_size, - buffer->transaction ? "active" : "delivered"); + buffer->data); } -static void print_binder_work(struct seq_file *m, const char *prefix, - const char *transaction_prefix, - struct binder_work *w) +static void print_binder_work_ilocked(struct seq_file *m, + struct binder_proc *proc, + const char *prefix, + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -3972,8 +5735,16 @@ static void print_binder_work(struct seq_file *m, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); - print_binder_transaction(m, transaction_prefix, t); + print_binder_transaction_ilocked( + m, proc, transaction_prefix, t); break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + seq_printf(m, "%stransaction error: %u\n", + prefix, e->cmd); + } break; case BINDER_WORK_TRANSACTION_COMPLETE: seq_printf(m, "%stransaction complete\n", prefix); break; @@ -3998,40 +5769,46 @@ static void print_binder_work(struct seq_file *m, const char *prefix, } } -static void print_binder_thread(struct seq_file *m, - struct binder_thread *thread, - int print_always) +static void print_binder_thread_ilocked(struct seq_file *m, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; size_t start_pos = m->count; size_t header_pos; - seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); + seq_printf(m, " thread %d: l %02x need_return %d tr %d\n", + thread->pid, thread->looper, + thread->looper_need_return, + atomic_read(&thread->tmp_ref)); header_pos = m->count; t = thread->transaction_stack; while (t) { if (t->from == thread) { - print_binder_transaction(m, - " outgoing transaction", t); + print_binder_transaction_ilocked(m, thread->proc, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - print_binder_transaction(m, + print_binder_transaction_ilocked(m, thread->proc, " incoming transaction", t); t = t->to_parent; } else { - print_binder_transaction(m, " bad transaction", t); + print_binder_transaction_ilocked(m, thread->proc, + " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { - print_binder_work(m, " ", " pending transaction", w); + print_binder_work_ilocked(m, thread->proc, " ", + " pending transaction", w); } if (!print_always && m->count == header_pos) m->count = start_pos; } -static void print_binder_node(struct seq_file *m, struct binder_node *node) +static void print_binder_node_nilocked(struct seq_file *m, + struct binder_node *node) { struct binder_ref *ref; struct binder_work *w; @@ -4041,27 +5818,35 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d", node->debug_id, (u64)node->ptr, (u64)node->cookie, + node->sched_policy, node->min_priority, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, - node->internal_strong_refs, count); + node->internal_strong_refs, count, node->tmp_refs); if (count) { seq_puts(m, " proc"); hlist_for_each_entry(ref, &node->refs, node_entry) seq_printf(m, " %d", ref->proc->pid); } seq_puts(m, "\n"); - list_for_each_entry(w, &node->async_todo, entry) - print_binder_work(m, " ", - " pending async transaction", w); + if (node->proc) { + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work_ilocked(m, node->proc, " ", + " pending async transaction", w); + } } -static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) +static void print_binder_ref_olocked(struct seq_file *m, + struct binder_ref *ref) { + binder_node_lock(ref->node); seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n", - ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", - ref->node->debug_id, ref->strong, ref->weak, ref->death); + ref->data.debug_id, ref->data.desc, + ref->node->proc ? "" : "dead ", + ref->node->debug_id, ref->data.strong, + ref->data.weak, ref->death); + binder_node_unlock(ref->node); } static void print_binder_proc(struct seq_file *m, @@ -4071,36 +5856,63 @@ static void print_binder_proc(struct seq_file *m, struct rb_node *n; size_t start_pos = m->count; size_t header_pos; + struct binder_node *last_node = NULL; seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); header_pos = m->count; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) - print_binder_thread(m, rb_entry(n, struct binder_thread, + print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, rb_node), print_all); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); - if (print_all || node->has_async_transaction) - print_binder_node(m, node); - } + if (!print_all && !node->has_async_transaction) + continue; + + /* + * take a temporary reference on the node so it + * survives and isn't removed from the tree + * while we print it. + */ + binder_inc_node_tmpref_ilocked(node); + /* Need to drop inner lock to take node lock */ + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + binder_node_inner_lock(node); + print_binder_node_nilocked(m, node); + binder_node_inner_unlock(node); + last_node = node; + binder_inner_proc_lock(proc); + } + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + if (print_all) { + binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) - print_binder_ref(m, rb_entry(n, struct binder_ref, - rb_node_desc)); + print_binder_ref_olocked(m, rb_entry(n, + struct binder_ref, + rb_node_desc)); + binder_proc_unlock(proc); } - for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) - print_binder_buffer(m, " buffer", - rb_entry(n, struct binder_buffer, rb_node)); + binder_alloc_print_allocated(m, &proc->alloc); + binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) - print_binder_work(m, " ", " pending transaction", w); + print_binder_work_ilocked(m, proc, " ", + " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { seq_puts(m, " has delivered dead binder\n"); break; } + binder_inner_proc_unlock(proc); if (!print_all && m->count == header_pos) m->count = start_pos; } @@ -4123,7 +5935,8 @@ static const char * const binder_return_strings[] = { "BR_FINISHED", "BR_DEAD_BINDER", "BR_CLEAR_DEATH_NOTIFICATION_DONE", - "BR_FAILED_REPLY" + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", }; static const char * const binder_command_strings[] = { @@ -4158,54 +5971,45 @@ static const char * const binder_objstat_strings[] = { "transaction_complete" }; -static void add_binder_stats(struct binder_stats *from, struct binder_stats *to) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(to->bc); i++) - to->bc[i] += from->bc[i]; - - for (i = 0; i < ARRAY_SIZE(to->br); i++) - to->br[i] += from->br[i]; -} - static void print_binder_stats(struct seq_file *m, const char *prefix, - struct binder_stats *stats, - struct binder_obj_stats *obj_stats) + struct binder_stats *stats) { int i; BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { - if (stats->bc[i]) + int temp = atomic_read(&stats->bc[i]); + + if (temp) seq_printf(m, "%s%s: %d\n", prefix, - binder_command_strings[i], stats->bc[i]); + binder_command_strings[i], temp); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { - if (stats->br[i]) + int temp = atomic_read(&stats->br[i]); + + if (temp) seq_printf(m, "%s%s: %d\n", prefix, - binder_return_strings[i], stats->br[i]); + binder_return_strings[i], temp); } - if (!obj_stats) - return; - - BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != ARRAY_SIZE(binder_objstat_strings)); - BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != - ARRAY_SIZE(obj_stats->obj_deleted)); - for (i = 0; i < ARRAY_SIZE(obj_stats->obj_created); i++) { - int obj_created = atomic_read(&obj_stats->obj_created[i]); - int obj_deleted = atomic_read(&obj_stats->obj_deleted[i]); - - if (obj_created || obj_deleted) - seq_printf(m, "%s%s: active %d total %d\n", prefix, - binder_objstat_strings[i], - obj_created - obj_deleted, obj_created); + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + ARRAY_SIZE(stats->obj_deleted)); + for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { + int created = atomic_read(&stats->obj_created[i]); + int deleted = atomic_read(&stats->obj_deleted[i]); + + if (created || deleted) + seq_printf(m, "%s%s: active %d total %d\n", + prefix, + binder_objstat_strings[i], + created - deleted, + created); } } @@ -4213,231 +6017,199 @@ static void print_binder_proc_stats(struct seq_file *m, struct binder_proc *proc) { struct binder_work *w; + struct binder_thread *thread; struct rb_node *n; - int count, strong, weak; + int count, strong, weak, ready_threads; + size_t free_async_space = + binder_alloc_get_free_async_space(&proc->alloc); seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); + //seq_printf(m, "context FIFO: %d\n", proc->context->inherit_fifo_prio); count = 0; + ready_threads = 0; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; + + list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) + ready_threads++; + seq_printf(m, " threads: %d\n", count); seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, - proc->ready_threads, proc->free_async_space); + ready_threads, + free_async_space); count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; + binder_inner_proc_unlock(proc); seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; + binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); count++; - strong += ref->strong; - weak += ref->weak; + strong += ref->data.strong; + weak += ref->data.weak; } + binder_proc_unlock(proc); seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); - count = 0; - for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) - count++; + count = binder_alloc_get_allocated_count(&proc->alloc); seq_printf(m, " buffers: %d\n", count); count = 0; + binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) { - switch (w->type) { - case BINDER_WORK_TRANSACTION: + if (w->type == BINDER_WORK_TRANSACTION) count++; - break; - default: - break; - } } + binder_inner_proc_unlock(proc); seq_printf(m, " pending transactions: %d\n", count); - print_binder_stats(m, " ", &proc->stats, NULL); + print_binder_stats(m, " ", &proc->stats); } -static int binder_state_show(struct seq_file *m, void *unused) +int binder_state_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *proc; struct binder_node *node; - int do_lock = !binder_debug_no_lock; - bool wrote_dead_nodes_header = false; + struct binder_node *last_node = NULL; seq_puts(m, "binder state:\n"); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); - if (!wrote_dead_nodes_header && - !hlist_empty(&context->binder_dead_nodes)) { - seq_puts(m, "dead nodes:\n"); - wrote_dead_nodes_header = true; - } - hlist_for_each_entry(node, &context->binder_dead_nodes, - dead_node) - print_binder_node(m, node); - - if (do_lock) - binder_unlock(context, __func__); - } - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); + spin_lock(&binder_dead_nodes_lock); + if (!hlist_empty(&binder_dead_nodes)) + seq_puts(m, "dead nodes:\n"); + hlist_for_each_entry(node, &binder_dead_nodes, dead_node) { + /* + * take a temporary reference on the node so it + * survives and isn't removed from the list + * while we print it. + */ + node->tmp_refs++; + spin_unlock(&binder_dead_nodes_lock); + if (last_node) + binder_put_node(last_node); + binder_node_lock(node); + print_binder_node_nilocked(m, node); + binder_node_unlock(node); + last_node = node; + spin_lock(&binder_dead_nodes_lock); + } + spin_unlock(&binder_dead_nodes_lock); + if (last_node) + binder_put_node(last_node); + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, 1); + mutex_unlock(&binder_procs_lock); - hlist_for_each_entry(proc, &context->binder_procs, proc_node) - print_binder_proc(m, proc, 1); - if (do_lock) - binder_unlock(context, __func__); - } return 0; } -static int binder_stats_show(struct seq_file *m, void *unused) +int binder_stats_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *proc; - struct binder_stats total_binder_stats; - int do_lock = !binder_debug_no_lock; - - memset(&total_binder_stats, 0, sizeof(struct binder_stats)); - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); - - add_binder_stats(&context->binder_stats, &total_binder_stats); - - if (do_lock) - binder_unlock(context, __func__); - } seq_puts(m, "binder stats:\n"); - print_binder_stats(m, "", &total_binder_stats, &binder_obj_stats); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); + print_binder_stats(m, "", &binder_stats); + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc_stats(m, proc); + mutex_unlock(&binder_procs_lock); - hlist_for_each_entry(proc, &context->binder_procs, proc_node) - print_binder_proc_stats(m, proc); - if (do_lock) - binder_unlock(context, __func__); - } return 0; } -static int binder_transactions_show(struct seq_file *m, void *unused) +int binder_transactions_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *proc; - int do_lock = !binder_debug_no_lock; seq_puts(m, "binder transactions:\n"); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, 0); + mutex_unlock(&binder_procs_lock); - hlist_for_each_entry(proc, &context->binder_procs, proc_node) - print_binder_proc(m, proc, 0); - if (do_lock) - binder_unlock(context, __func__); - } return 0; } -static int binder_proc_show(struct seq_file *m, void *unused) +static int proc_show(struct seq_file *m, void *unused) { - struct binder_device *device; - struct binder_context *context; struct binder_proc *itr; int pid = (unsigned long)m->private; - int do_lock = !binder_debug_no_lock; - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - if (do_lock) - binder_lock(context, __func__); - hlist_for_each_entry(itr, &context->binder_procs, proc_node) { - if (itr->pid == pid) { - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, itr, 1); - } + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(itr, &binder_procs, proc_node) { + if (itr->pid == pid) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, itr, 1); } - if (do_lock) - binder_unlock(context, __func__); } + mutex_unlock(&binder_procs_lock); + return 0; } static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { + int debug_id = READ_ONCE(e->debug_id_done); + /* + * read barrier to guarantee debug_id_done read before + * we print the log values + */ + smp_rmb(); seq_printf(m, - "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d\n", + "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d ret %d/%d l=%d", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->context_name, - e->to_node, e->target_handle, e->data_size, e->offsets_size); + e->to_node, e->target_handle, e->data_size, e->offsets_size, + e->return_error, e->return_error_param, + e->return_error_line); + /* + * read-barrier to guarantee read of debug_id_done after + * done printing the fields of the entry + */ + smp_rmb(); + seq_printf(m, debug_id && debug_id == READ_ONCE(e->debug_id_done) ? + "\n" : " (incomplete)\n"); } -static int print_binder_transaction_log(struct seq_file *m, - struct binder_transaction_log *log) +int binder_transaction_log_show(struct seq_file *m, void *unused) { + struct binder_transaction_log *log = m->private; + unsigned int log_cur = atomic_read(&log->cur); + unsigned int count; + unsigned int cur; int i; - if (log->full) { - for (i = log->next; i < ARRAY_SIZE(log->entry); i++) - print_binder_transaction_log_entry(m, &log->entry[i]); - } - for (i = 0; i < log->next; i++) - print_binder_transaction_log_entry(m, &log->entry[i]); - return 0; -} - -static int binder_transaction_log_show(struct seq_file *m, void *unused) -{ - struct binder_device *device; - struct binder_context *context; - - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - print_binder_transaction_log(m, &context->transaction_log); - } - return 0; -} -static int binder_failed_transaction_log_show(struct seq_file *m, void *unused) -{ - struct binder_device *device; - struct binder_context *context; + count = log_cur + 1; + cur = count < ARRAY_SIZE(log->entry) && !log->full ? + 0 : count % ARRAY_SIZE(log->entry); + if (count > ARRAY_SIZE(log->entry) || log->full) + count = ARRAY_SIZE(log->entry); + for (i = 0; i < count; i++) { + unsigned int index = cur++ % ARRAY_SIZE(log->entry); - hlist_for_each_entry(device, &binder_devices, hlist) { - context = &device->context; - print_binder_transaction_log(m, - &context->transaction_log_failed); + print_binder_transaction_log_entry(m, &log->entry[index]); } return 0; } -static const struct file_operations binder_fops = { +const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, @@ -4448,24 +6220,10 @@ static const struct file_operations binder_fops = { .release = binder_release, }; -BINDER_DEBUG_ENTRY(state); -BINDER_DEBUG_ENTRY(stats); -BINDER_DEBUG_ENTRY(transactions); -BINDER_DEBUG_ENTRY(transaction_log); -BINDER_DEBUG_ENTRY(failed_transaction_log); - -static void __init free_binder_device(struct binder_device *device) -{ - if (device->context.binder_deferred_workqueue) - destroy_workqueue(device->context.binder_deferred_workqueue); - kfree(device); -} - static int __init init_binder_device(const char *name) { int ret; struct binder_device *binder_device; - struct binder_context *context; binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL); if (!binder_device) @@ -4475,65 +6233,35 @@ static int __init init_binder_device(const char *name) binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; binder_device->miscdev.name = name; - context = &binder_device->context; - context->binder_context_mgr_uid = INVALID_UID; - context->name = name; - - mutex_init(&context->binder_main_lock); - mutex_init(&context->binder_deferred_lock); - mutex_init(&context->binder_mmap_lock); - - context->binder_deferred_workqueue = - create_singlethread_workqueue(name); - - if (!context->binder_deferred_workqueue) { - ret = -ENOMEM; - goto err_create_singlethread_workqueue_failed; - } - - INIT_HLIST_HEAD(&context->binder_procs); - INIT_HLIST_HEAD(&context->binder_dead_nodes); - INIT_HLIST_HEAD(&context->binder_deferred_list); - INIT_WORK(&context->deferred_work, binder_deferred_func); + refcount_set(&binder_device->ref, 1); + binder_device->context.binder_context_mgr_uid = INVALID_UID; + binder_device->context.name = name; + mutex_init(&binder_device->context.context_mgr_node_lock); ret = misc_register(&binder_device->miscdev); if (ret < 0) { - goto err_misc_register_failed; + kfree(binder_device); + return ret; } hlist_add_head(&binder_device->hlist, &binder_devices); - return ret; - -err_create_singlethread_workqueue_failed: -err_misc_register_failed: - free_binder_device(binder_device); return ret; } static int __init binder_init(void) { - int ret = 0; - char *device_name, *device_names; + int ret; + char *device_name, *device_names, *device_tmp; struct binder_device *device; struct hlist_node *tmp; - /* - * Copy the module_parameter string, because we don't want to - * tokenize it in-place. - */ - device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); - if (!device_names) + atomic_set(&binder_transaction_log.cur, ~0U); + atomic_set(&binder_transaction_log_failed.cur, ~0U); + binder_deferred_workqueue = create_singlethread_workqueue("binder"); + if (!binder_deferred_workqueue) return -ENOMEM; - strcpy(device_names, binder_devices_param); - - while ((device_name = strsep(&device_names, ","))) { - ret = init_binder_device(device_name); - if (ret) - goto err_init_binder_device_failed; - } - binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); if (binder_debugfs_dir_entry_root) binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", @@ -4541,30 +6269,47 @@ static int __init binder_init(void) if (binder_debugfs_dir_entry_root) { debugfs_create_file("state", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_state_fops); debugfs_create_file("stats", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_stats_fops); debugfs_create_file("transactions", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_transactions_fops); debugfs_create_file("transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, - NULL, + &binder_transaction_log, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, - NULL, - &binder_failed_transaction_log_fops); + &binder_transaction_log_failed, + &binder_transaction_log_fops); + } + + /* + * Copy the module_parameter string, because we don't want to + * tokenize it in-place. + */ + device_names = kstrdup(binder_devices_param, GFP_KERNEL); + if (!device_names) { + ret = -ENOMEM; + goto err_alloc_device_names_failed; + } + + device_tmp = device_names; + while ((device_name = strsep(&device_tmp, ","))) { + ret = init_binder_device(device_name); + if (ret) + goto err_init_binder_device_failed; } return ret; @@ -4573,9 +6318,16 @@ err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); hlist_del(&device->hlist); - free_binder_device(device); + kfree(device); } + kfree(device_names); + +err_alloc_device_names_failed: + debugfs_remove_recursive(binder_debugfs_dir_entry_root); + + destroy_workqueue(binder_deferred_workqueue); + return ret; } diff --git a/drivers/android/binder.h b/drivers/android/binder.h new file mode 100644 index 0000000000000000000000000000000000000000..e76ed664c69aea026cdd6d17f0ce844e477c9368 --- /dev/null +++ b/drivers/android/binder.h @@ -0,0 +1,26 @@ + /* + * Copyright (C) 2008 Google, Inc. + * + * Based on, but no longer compatible with, the original + * OpenBinder.org binder driver interface, which is: + * + * Copyright (c) 2005 Palmsource, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_BINDER_H +#define _LINUX_BINDER_H + +#include + +#endif /* _LINUX_BINDER_H */ + diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c new file mode 100644 index 0000000000000000000000000000000000000000..03f28867bc0795ce0e50f3b4ab244692fba9b7ae --- /dev/null +++ b/drivers/android/binder_alloc.c @@ -0,0 +1,881 @@ + /* binder_alloc.c + * + * Android IPC Subsystem + * + * Copyright (C) 2007-2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "binder_alloc.h" +#include "binder_trace.h" + +static DEFINE_MUTEX(binder_alloc_mmap_lock); + +enum { + BINDER_DEBUG_OPEN_CLOSE = 1U << 1, + BINDER_DEBUG_BUFFER_ALLOC = 1U << 2, + BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 3, +}; +static uint32_t binder_alloc_debug_mask; + +module_param_named(debug_mask, binder_alloc_debug_mask, + uint, 0644); + +#define binder_alloc_debug(mask, x...) \ + do { \ + if (binder_alloc_debug_mask & mask) \ + pr_info_ratelimited(x); \ + } while (0) + +static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) +{ + return list_entry(buffer->entry.next, struct binder_buffer, entry); +} + +static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) +{ + return list_entry(buffer->entry.prev, struct binder_buffer, entry); +} + +static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + if (list_is_last(&buffer->entry, &alloc->buffers)) + return (u8 *)alloc->buffer + + alloc->buffer_size - (u8 *)buffer->data; + return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data; +} + +static void binder_insert_free_buffer(struct binder_alloc *alloc, + struct binder_buffer *new_buffer) +{ + struct rb_node **p = &alloc->free_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + size_t buffer_size; + size_t new_buffer_size; + + BUG_ON(!new_buffer->free); + + new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: add free buffer, size %zd, at %pK\n", + alloc->pid, new_buffer_size, new_buffer); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + if (new_buffer_size < buffer_size) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &alloc->free_buffers); +} + +static void binder_insert_allocated_buffer_locked( + struct binder_alloc *alloc, struct binder_buffer *new_buffer) +{ + struct rb_node **p = &alloc->allocated_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + + BUG_ON(new_buffer->free); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (new_buffer->data < buffer->data) + p = &parent->rb_left; + else if (new_buffer->data > buffer->data) + p = &parent->rb_right; + else + BUG(); + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers); +} + +static struct binder_buffer *binder_alloc_prepare_to_free_locked( + struct binder_alloc *alloc, + uintptr_t user_ptr) +{ + struct rb_node *n = alloc->allocated_buffers.rb_node; + struct binder_buffer *buffer; + void *kern_ptr; + + kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (kern_ptr < buffer->data) + n = n->rb_left; + else if (kern_ptr > buffer->data) + n = n->rb_right; + else { + /* + * Guard against user threads attempting to + * free the buffer when in use by kernel or + * after it's already been freed. + */ + if (!buffer->allow_user_free) + return ERR_PTR(-EPERM); + buffer->allow_user_free = 0; + return buffer; + } + } + return NULL; +} + +/** + * binder_alloc_buffer_lookup() - get buffer given user ptr + * @alloc: binder_alloc for this proc + * @user_ptr: User pointer to buffer data + * + * Validate userspace pointer to buffer data and return buffer corresponding to + * that user pointer. Search the rb tree for buffer that matches user data + * pointer. + * + * Return: Pointer to buffer or NULL + */ +struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, + uintptr_t user_ptr) +{ + struct binder_buffer *buffer; + + mutex_lock(&alloc->mutex); + buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); + mutex_unlock(&alloc->mutex); + return buffer; +} + +static int binder_update_page_range(struct binder_alloc *alloc, int allocate, + void *start, void *end, + struct vm_area_struct *vma) +{ + void *page_addr; + unsigned long user_page_addr; + struct page **page; + struct mm_struct *mm = NULL; + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: %s pages %pK-%pK\n", alloc->pid, + allocate ? "allocate" : "free", start, end); + + if (end <= start) + return 0; + + trace_binder_update_page_range(alloc, allocate, start, end); + + if (vma) + mm = NULL; + else + mm = get_task_mm(alloc->tsk); + + if (mm) { + down_read(&mm->mmap_sem); + vma = alloc->vma; + if (vma && mm != alloc->vma_vm_mm) { + pr_err("%d: vma mm and task mm mismatch\n", + alloc->pid); + vma = NULL; + } + } + + if (allocate == 0) + goto free_range; + + if (vma == NULL) { + pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", + alloc->pid); + goto err_no_vma; + } + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + int ret; + + page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; + + BUG_ON(*page); + *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (*page == NULL) { + pr_err("%d: binder_alloc_buf failed for page at %pK\n", + alloc->pid, page_addr); + goto err_alloc_page_failed; + } + + if (WARN_ON(!vma)) + goto err_page_ptr_cleared; + + ret = map_kernel_range_noflush((unsigned long)page_addr, + PAGE_SIZE, PAGE_KERNEL, page); + flush_cache_vmap((unsigned long)page_addr, + (unsigned long)page_addr + PAGE_SIZE); + if (ret != 1) { + pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", + alloc->pid, page_addr); + goto err_map_kernel_failed; + } + user_page_addr = + (uintptr_t)page_addr + alloc->user_buffer_offset; + ret = vm_insert_page(vma, user_page_addr, page[0]); + if (ret) { + pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", + alloc->pid, user_page_addr); + goto err_vm_insert_page_failed; + } + /* vm_insert_page does not seem to increment the refcount */ + } + if (mm) { + up_read(&mm->mmap_sem); + mmput(mm); + } + return 0; + +free_range: + + for (page_addr = end - PAGE_SIZE; 1; page_addr -= PAGE_SIZE) { + page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; + if (vma) + zap_page_range(vma, (uintptr_t)page_addr + + alloc->user_buffer_offset, PAGE_SIZE, NULL); +err_vm_insert_page_failed: + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); +err_map_kernel_failed: + __free_page(*page); + *page = NULL; +err_alloc_page_failed: +err_page_ptr_cleared: + if (page_addr == start) + break; + } +err_no_vma: + if (mm) { + up_read(&mm->mmap_sem); + mmput(mm); + } + return vma ? -ENOMEM : -ESRCH; +} + +static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) +{ + /* + * Find the amount and size of buffers allocated by the current caller; + * The idea is that once we cross the threshold, whoever is responsible + * for the low async space is likely to try to send another async txn, + * and at some point we'll catch them in the act. This is more efficient + * than keeping a map per pid. + */ + struct rb_node *n = alloc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t total_alloc_size = 0; + size_t num_buffers = 0; + + for (n = rb_first(&alloc->allocated_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + if (buffer->pid != pid) + continue; + if (!buffer->async_transaction) + continue; + total_alloc_size += binder_alloc_buffer_size(alloc, buffer) + + sizeof(struct binder_buffer); + num_buffers++; + } + + /* + * Warn if this pid has more than 50 transactions, or more than 50% of + * async space (which is 25% of total buffer size). + */ + if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) { + pr_err("%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n", + alloc->pid, pid, num_buffers, total_alloc_size); + } +} + +static struct binder_buffer *binder_alloc_new_buf_locked( + struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async, + int pid) +{ + struct rb_node *n = alloc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t buffer_size; + struct rb_node *best_fit = NULL; + void *has_page_addr; + void *end_page_addr; + size_t size, data_offsets_size; + int ret; + + if (alloc->vma == NULL) { + pr_err("%d: binder_alloc_buf, no vma\n", + alloc->pid); + return ERR_PTR(-ESRCH); + } + + data_offsets_size = ALIGN(data_size, sizeof(void *)) + + ALIGN(offsets_size, sizeof(void *)); + + if (data_offsets_size < data_size || data_offsets_size < offsets_size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid size %zd-%zd\n", + alloc->pid, data_size, offsets_size); + return ERR_PTR(-EINVAL); + } + size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); + if (size < data_offsets_size || size < extra_buffers_size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid extra_buffers_size %zd\n", + alloc->pid, extra_buffers_size); + return ERR_PTR(-EINVAL); + } + if (is_async && + alloc->free_async_space < size + sizeof(struct binder_buffer)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd failed, no async space left\n", + alloc->pid, size); + return ERR_PTR(-ENOSPC); + } + + /* Pad 0-size buffers so they get assigned unique addresses */ + size = max(size, sizeof(void *)); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + if (size < buffer_size) { + best_fit = n; + n = n->rb_left; + } else if (size > buffer_size) + n = n->rb_right; + else { + best_fit = n; + break; + } + } + if (best_fit == NULL) { + size_t allocated_buffers = 0; + size_t largest_alloc_size = 0; + size_t total_alloc_size = 0; + size_t free_buffers = 0; + size_t largest_free_size = 0; + size_t total_free_size = 0; + + for (n = rb_first(&alloc->allocated_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + allocated_buffers++; + total_alloc_size += buffer_size; + if (buffer_size > largest_alloc_size) + largest_alloc_size = buffer_size; + } + for (n = rb_first(&alloc->free_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + free_buffers++; + total_free_size += buffer_size; + if (buffer_size > largest_free_size) + largest_free_size = buffer_size; + } + pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", + alloc->pid, size); + pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", + total_alloc_size, allocated_buffers, largest_alloc_size, + total_free_size, free_buffers, largest_free_size); + return ERR_PTR(-ENOSPC); + } + if (n == NULL) { + buffer = rb_entry(best_fit, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + } + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", + alloc->pid, size, buffer, buffer_size); + + has_page_addr = + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); + WARN_ON(n && buffer_size != size); + end_page_addr = + (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + if (end_page_addr > has_page_addr) + end_page_addr = has_page_addr; + ret = binder_update_page_range(alloc, 1, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL); + if (ret) + return ERR_PTR(ret); + + if (buffer_size != size) { + struct binder_buffer *new_buffer; + + new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!new_buffer) { + pr_err("%s: %d failed to alloc new buffer struct\n", + __func__, alloc->pid); + goto err_alloc_buf_struct_failed; + } + new_buffer->data = (u8 *)buffer->data + size; + list_add(&new_buffer->entry, &buffer->entry); + new_buffer->free = 1; + binder_insert_free_buffer(alloc, new_buffer); + } + + rb_erase(best_fit, &alloc->free_buffers); + buffer->free = 0; + buffer->allow_user_free = 0; + binder_insert_allocated_buffer_locked(alloc, buffer); + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got %pK\n", + alloc->pid, size, buffer); + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; + buffer->async_transaction = is_async; + buffer->extra_buffers_size = extra_buffers_size; + buffer->pid = pid; + if (is_async) { + alloc->free_async_space -= size + sizeof(struct binder_buffer); + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_alloc_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); + if (alloc->free_async_space < alloc->buffer_size / 10) { + /* + * Start detecting spammers once we have less than 20% + * of async space left (which is less than 10% of total + * buffer size). + */ + debug_low_async_space_locked(alloc, pid); + } + } + return buffer; + +err_alloc_buf_struct_failed: + binder_update_page_range(alloc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + end_page_addr, NULL); + return ERR_PTR(-ENOMEM); +} + +/** + * binder_alloc_new_buf() - Allocate a new binder buffer + * @alloc: binder_alloc for this proc + * @data_size: size of user data buffer + * @offsets_size: user specified buffer offset + * @extra_buffers_size: size of extra space for meta-data (eg, security context) + * @is_async: buffer for async transaction + * @pid: pid to attribute allocation to (used for debugging) + * + * Allocate a new buffer given the requested sizes. Returns + * the kernel version of the buffer pointer. The size allocated + * is the sum of the three given sizes (each rounded up to + * pointer-sized boundary) + * + * Return: The allocated buffer or %NULL if error + */ +struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async, + int pid) +{ + struct binder_buffer *buffer; + + mutex_lock(&alloc->mutex); + buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, + extra_buffers_size, is_async, pid); + mutex_unlock(&alloc->mutex); + return buffer; +} + +static void *buffer_start_page(struct binder_buffer *buffer) +{ + return (void *)((uintptr_t)buffer->data & PAGE_MASK); +} + +static void *prev_buffer_end_page(struct binder_buffer *buffer) +{ + return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK); +} + +static void binder_delete_free_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + struct binder_buffer *prev, *next = NULL; + bool to_free = true; + BUG_ON(alloc->buffers.next == &buffer->entry); + prev = binder_buffer_prev(buffer); + BUG_ON(!prev->free); + if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { + to_free = false; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK share page with %pK\n", + alloc->pid, buffer->data, prev->data); + } + + if (!list_is_last(&buffer->entry, &alloc->buffers)) { + next = binder_buffer_next(buffer); + if (buffer_start_page(next) == buffer_start_page(buffer)) { + to_free = false; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK share page with %pK\n", + alloc->pid, + buffer->data, + next->data); + } + } + + if (IS_ALIGNED((unsigned long)buffer->data, PAGE_SIZE)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer start %pK is page aligned\n", + alloc->pid, buffer->data); + to_free = false; + } + + if (to_free) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK do not share page with %pK or %pK\n", + alloc->pid, buffer->data, + prev->data, next ? next->data : NULL); + binder_update_page_range(alloc, 0, buffer_start_page(buffer), + buffer_start_page(buffer) + PAGE_SIZE, + NULL); + } + list_del(&buffer->entry); + kfree(buffer); +} + +static void binder_free_buf_locked(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + size_t size, buffer_size; + + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + size = ALIGN(buffer->data_size, sizeof(void *)) + + ALIGN(buffer->offsets_size, sizeof(void *)) + + ALIGN(buffer->extra_buffers_size, sizeof(void *)); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_free_buf %pK size %zd buffer_size %zd\n", + alloc->pid, buffer, size, buffer_size); + + BUG_ON(buffer->free); + BUG_ON(size > buffer_size); + BUG_ON(buffer->transaction != NULL); + BUG_ON(buffer->data < alloc->buffer); + BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size); + + if (buffer->async_transaction) { + alloc->free_async_space += size + sizeof(struct binder_buffer); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_free_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); + } + + binder_update_page_range(alloc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), + NULL); + + rb_erase(&buffer->rb_node, &alloc->allocated_buffers); + buffer->free = 1; + if (!list_is_last(&buffer->entry, &alloc->buffers)) { + struct binder_buffer *next = binder_buffer_next(buffer); + + if (next->free) { + rb_erase(&next->rb_node, &alloc->free_buffers); + binder_delete_free_buffer(alloc, next); + } + } + if (alloc->buffers.next != &buffer->entry) { + struct binder_buffer *prev = binder_buffer_prev(buffer); + + if (prev->free) { + binder_delete_free_buffer(alloc, buffer); + rb_erase(&prev->rb_node, &alloc->free_buffers); + buffer = prev; + } + } + binder_insert_free_buffer(alloc, buffer); +} + +/** + * binder_alloc_free_buf() - free a binder buffer + * @alloc: binder_alloc for this proc + * @buffer: kernel pointer to buffer + * + * Free the buffer allocated via binder_alloc_new_buffer() + */ +void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + mutex_lock(&alloc->mutex); + binder_free_buf_locked(alloc, buffer); + mutex_unlock(&alloc->mutex); +} + +/** + * binder_alloc_mmap_handler() - map virtual address space for proc + * @alloc: alloc structure for this proc + * @vma: vma passed to mmap() + * + * Called by binder_mmap() to initialize the space specified in + * vma for allocating binder buffers + * + * Return: + * 0 = success + * -EBUSY = address space already mapped + * -ENOMEM = failed to map memory to given address space + */ +int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma) +{ + int ret; + struct vm_struct *area; + const char *failure_string; + struct binder_buffer *buffer; + + mutex_lock(&binder_alloc_mmap_lock); + if (alloc->buffer) { + ret = -EBUSY; + failure_string = "already mapped"; + goto err_already_mapped; + } + + area = get_vm_area(vma->vm_end - vma->vm_start, VM_ALLOC); + if (area == NULL) { + ret = -ENOMEM; + failure_string = "get_vm_area"; + goto err_get_vm_area_failed; + } + alloc->buffer = area->addr; + alloc->user_buffer_offset = + vma->vm_start - (uintptr_t)alloc->buffer; + mutex_unlock(&binder_alloc_mmap_lock); + + alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start, + SZ_4M); + alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE, + sizeof(alloc->pages[0]), + GFP_KERNEL); + if (alloc->pages == NULL) { + ret = -ENOMEM; + failure_string = "alloc page array"; + goto err_alloc_pages_failed; + } + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + failure_string = "alloc buffer struct"; + goto err_alloc_buf_struct_failed; + } + + buffer->data = alloc->buffer; + list_add(&buffer->entry, &alloc->buffers); + buffer->free = 1; + binder_insert_free_buffer(alloc, buffer); + alloc->free_async_space = alloc->buffer_size / 2; + barrier(); + alloc->vma = vma; + alloc->vma_vm_mm = vma->vm_mm; + /* Same as mmgrab() in later kernel versions */ + atomic_inc(&alloc->vma_vm_mm->mm_count); + + return 0; + +err_alloc_buf_struct_failed: + kfree(alloc->pages); + alloc->pages = NULL; +err_alloc_pages_failed: + mutex_lock(&binder_alloc_mmap_lock); + vfree(alloc->buffer); + alloc->buffer = NULL; +err_get_vm_area_failed: +err_already_mapped: + mutex_unlock(&binder_alloc_mmap_lock); + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, + alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret); + return ret; +} + + +void binder_alloc_deferred_release(struct binder_alloc *alloc) +{ + struct rb_node *n; + int buffers, page_count; + struct binder_buffer *buffer; + + BUG_ON(alloc->vma); + + buffers = 0; + mutex_lock(&alloc->mutex); + while ((n = rb_first(&alloc->allocated_buffers))) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + + /* Transaction should already have been freed */ + BUG_ON(buffer->transaction); + + binder_free_buf_locked(alloc, buffer); + buffers++; + } + + while (!list_empty(&alloc->buffers)) { + buffer = list_first_entry(&alloc->buffers, + struct binder_buffer, entry); + WARN_ON(!buffer->free); + + list_del(&buffer->entry); + WARN_ON_ONCE(!list_empty(&alloc->buffers)); + kfree(buffer); + } + + page_count = 0; + if (alloc->pages) { + int i; + + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { + void *page_addr; + + if (!alloc->pages[i]) + continue; + + page_addr = alloc->buffer + i * PAGE_SIZE; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%s: %d: page %d at %pK not freed\n", + __func__, alloc->pid, i, page_addr); + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); + __free_page(alloc->pages[i]); + page_count++; + } + kfree(alloc->pages); + vfree(alloc->buffer); + } + mutex_unlock(&alloc->mutex); + + binder_alloc_debug(BINDER_DEBUG_OPEN_CLOSE, + "%s: %d buffers %d, pages %d\n", + __func__, alloc->pid, buffers, page_count); +} + +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) +{ + seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->extra_buffers_size, + buffer->transaction ? "active" : "delivered"); +} + +/** + * binder_alloc_print_allocated() - print buffer info + * @m: seq_file for output via seq_printf() + * @alloc: binder_alloc for this proc + * + * Prints information about every buffer associated with + * the binder_alloc state to the given seq_file + */ +void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc) +{ + struct rb_node *n; + + mutex_lock(&alloc->mutex); + for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); + mutex_unlock(&alloc->mutex); +} + +/** + * binder_alloc_get_allocated_count() - return count of buffers + * @alloc: binder_alloc for this proc + * + * Return: count of allocated buffers + */ +int binder_alloc_get_allocated_count(struct binder_alloc *alloc) +{ + struct rb_node *n; + int count = 0; + + mutex_lock(&alloc->mutex); + for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) + count++; + mutex_unlock(&alloc->mutex); + return count; +} + + +/** + * binder_alloc_vma_close() - invalidate address space + * @alloc: binder_alloc for this proc + * + * Called from binder_vma_close() when releasing address space. + * Clears alloc->vma to prevent new incoming transactions from + * allocating more buffers. + */ +void binder_alloc_vma_close(struct binder_alloc *alloc) +{ + WRITE_ONCE(alloc->vma, NULL); + WRITE_ONCE(alloc->vma_vm_mm, NULL); +} + +/** + * binder_alloc_init() - called by binder_open() for per-proc initialization + * @alloc: binder_alloc for this proc + * + * Called from binder_open() to initialize binder_alloc fields for + * new binder proc + */ +void binder_alloc_init(struct binder_alloc *alloc) +{ + alloc->tsk = current->group_leader; + alloc->pid = current->group_leader->pid; + mutex_init(&alloc->mutex); + INIT_LIST_HEAD(&alloc->buffers); +} + diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h new file mode 100644 index 0000000000000000000000000000000000000000..8f23c184ec728eaa16818a2418e36ff39362b5a0 --- /dev/null +++ b/drivers/android/binder_alloc.h @@ -0,0 +1,170 @@ + /* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_BINDER_ALLOC_H +#define _LINUX_BINDER_ALLOC_H + +#include +#include +#include +#include +#include +#include + +struct binder_transaction; + +/** + * struct binder_buffer - buffer used for binder transactions + * @entry: entry alloc->buffers + * @rb_node: node for allocated_buffers/free_buffers rb trees + * @free: %true if buffer is free + * @allow_user_free: %true if user is allowed to free buffer + * @async_transaction: %true if buffer is in use for an async txn + * @debug_id: unique ID for debugging + * @transaction: pointer to associated struct binder_transaction + * @target_node: struct binder_node associated with this buffer + * @data_size: size of @transaction data + * @offsets_size: size of array of offsets + * @extra_buffers_size: size of space for other objects (like sg lists) + * @data: pointer to base of buffer space + * @pid: pid to attribute the buffer to (caller) + * + * Bookkeeping structure for binder transaction buffers + */ +struct binder_buffer { + struct list_head entry; /* free and allocated entries by address */ + struct rb_node rb_node; /* free entry by size or allocated entry */ + /* by address */ + unsigned free:1; + unsigned allow_user_free:1; + unsigned async_transaction:1; + unsigned debug_id:29; + + struct binder_transaction *transaction; + + struct binder_node *target_node; + size_t data_size; + size_t offsets_size; + size_t extra_buffers_size; + void *data; + int pid; +}; + +/** + * struct binder_alloc - per-binder proc state for binder allocator + * @vma: vm_area_struct passed to mmap_handler + * (invarient after mmap) + * @tsk: tid for task that called init for this proc + * (invariant after init) + * @vma_vm_mm: copy of vma->vm_mm (invarient after mmap) + * @buffer: base of per-proc address space mapped via mmap + * @user_buffer_offset: offset between user and kernel VAs for buffer + * @buffers: list of all buffers for this proc + * @free_buffers: rb tree of buffers available for allocation + * sorted by size + * @allocated_buffers: rb tree of allocated buffers sorted by address + * @free_async_space: VA space available for async buffers. This is + * initialized at mmap time to 1/2 the full VA space + * @pages: array of physical page addresses for each + * page of mmap'd space + * @buffer_size: size of address space specified via mmap + * @pid: pid for associated binder_proc (invariant after init) + * + * Bookkeeping structure for per-proc address space management for binder + * buffers. It is normally initialized during binder_init() and binder_mmap() + * calls. The address space is used for both user-visible buffers and for + * struct binder_buffer objects used to track the user buffers + */ +struct binder_alloc { + struct mutex mutex; + struct task_struct *tsk; + struct vm_area_struct *vma; + struct mm_struct *vma_vm_mm; + void *buffer; + ptrdiff_t user_buffer_offset; + struct list_head buffers; + struct rb_root free_buffers; + struct rb_root allocated_buffers; + size_t free_async_space; + struct page **pages; + size_t buffer_size; + uint32_t buffer_free; + int pid; +}; + +#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST +void binder_selftest_alloc(struct binder_alloc *alloc); +#else +static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} +#endif +extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async, + int pid); +extern void binder_alloc_init(struct binder_alloc *alloc); +extern void binder_alloc_vma_close(struct binder_alloc *alloc); +extern struct binder_buffer * +binder_alloc_prepare_to_free(struct binder_alloc *alloc, + uintptr_t user_ptr); +extern void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer); +extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma); +extern void binder_alloc_deferred_release(struct binder_alloc *alloc); +extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc); +extern void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc); + +/** + * binder_alloc_get_free_async_space() - get free space available for async + * @alloc: binder_alloc for this proc + * + * Return: the bytes remaining in the address-space for async transactions + */ +static inline size_t +binder_alloc_get_free_async_space(struct binder_alloc *alloc) +{ + size_t free_async_space; + + mutex_lock(&alloc->mutex); + free_async_space = alloc->free_async_space; + mutex_unlock(&alloc->mutex); + return free_async_space; +} + +/** + * binder_alloc_get_user_buffer_offset() - get offset between kernel/user addrs + * @alloc: binder_alloc for this proc + * + * Return: the offset between kernel and user-space addresses to use for + * virtual address conversion + */ +static inline ptrdiff_t +binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc) +{ + /* + * user_buffer_offset is constant if vma is set and + * undefined if vma is not set. It is possible to + * get here with !alloc->vma if the target process + * is dying while a transaction is being initiated. + * Returning the old value is ok in this case and + * the transaction will fail. + */ + return alloc->user_buffer_offset; +} + +#endif /* _LINUX_BINDER_ALLOC_H */ + diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c new file mode 100644 index 0000000000000000000000000000000000000000..eff5dea1509f104ca16d6cdd2a9cd2afdf44bada --- /dev/null +++ b/drivers/android/binder_alloc_selftest.c @@ -0,0 +1,270 @@ + /* binder_alloc_selftest.c + * + * Android IPC Subsystem + * + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include "binder_alloc.h" + +#define BUFFER_NUM 5 +#define BUFFER_MIN_SIZE (PAGE_SIZE / 8) + +static bool binder_selftest_run = true; +static int binder_selftest_failures; +static DEFINE_MUTEX(binder_selftest_lock); + +/** + * enum buf_end_align_type - Page alignment of a buffer + * end with regard to the end of the previous buffer. + * + * In the pictures below, buf2 refers to the buffer we + * are aligning. buf1 refers to previous buffer by addr. + * Symbol [ means the start of a buffer, ] means the end + * of a buffer, and | means page boundaries. + */ +enum buf_end_align_type { + /** + * @SAME_PAGE_UNALIGNED: The end of this buffer is on + * the same page as the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 ][ ... + * buf1 ]|[ buf2 ][ ... + */ + SAME_PAGE_UNALIGNED = 0, + /** + * @SAME_PAGE_ALIGNED: When the end of the previous buffer + * is not page aligned, the end of this buffer is on the + * same page as the end of the previous buffer and is page + * aligned. When the previous buffer is page aligned, the + * end of this buffer is aligned to the next page boundary. + * Examples: + * buf1 ][ buf2 ]| ... + * buf1 ]|[ buf2 ]| ... + */ + SAME_PAGE_ALIGNED, + /** + * @NEXT_PAGE_UNALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 ][ ... + */ + NEXT_PAGE_UNALIGNED, + /** + * @NEXT_PAGE_ALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is page aligned. Examples: + * buf1 ][ buf2 | buf2 ]| ... + * buf1 ]|[ buf2 | buf2 ]| ... + */ + NEXT_PAGE_ALIGNED, + /** + * @NEXT_NEXT_UNALIGNED: The end of this buffer is on + * the page that follows the page after the end of the + * previous buffer and is not page aligned. Examples: + * buf1 ][ buf2 | buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 | buf2 ][ ... + */ + NEXT_NEXT_UNALIGNED, + LOOP_END, +}; + +static void pr_err_size_seq(size_t *sizes, int *seq) +{ + int i; + + pr_err("alloc sizes: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%zu]", sizes[i]); + pr_cont("\n"); + pr_err("free seq: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%d]", seq[i]); + pr_cont("\n"); +} + +static bool check_buffer_pages_allocated(struct binder_alloc *alloc, + struct binder_buffer *buffer, + size_t size) +{ + void *page_addr, *end; + int page_index; + + end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + page_addr = buffer->data; + for (; page_addr < end; page_addr += PAGE_SIZE) { + page_index = (page_addr - alloc->buffer) / PAGE_SIZE; + if (!alloc->pages[page_index]) { + pr_err("incorrect alloc state at page index %d\n", + page_index); + return false; + } + } + return true; +} + +static void binder_selftest_alloc_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) { + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0); + if (IS_ERR(buffers[i]) || + !check_buffer_pages_allocated(alloc, buffers[i], + sizes[i])) { + pr_err_size_seq(sizes, seq); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) + binder_alloc_free_buf(alloc, buffers[seq[i]]); + + for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { + if ((!alloc->pages[i]) == (i == 0)) { + pr_err("incorrect free state at page index %d\n", i); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_alloc_free(struct binder_alloc *alloc, + size_t *sizes, int *seq) +{ + struct binder_buffer *buffers[BUFFER_NUM]; + + binder_selftest_alloc_buf(alloc, buffers, sizes, seq); + binder_selftest_free_buf(alloc, buffers, sizes, seq); +} + +static bool is_dup(int *seq, int index, int val) +{ + int i; + + for (i = 0; i < index; i++) { + if (seq[i] == val) + return true; + } + return false; +} + +/* Generate BUFFER_NUM factorial free orders. */ +static void binder_selftest_free_seq(struct binder_alloc *alloc, + size_t *sizes, int *seq, int index) +{ + int i; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_free(alloc, sizes, seq); + return; + } + for (i = 0; i < BUFFER_NUM; i++) { + if (is_dup(seq, index, i)) + continue; + seq[index] = i; + binder_selftest_free_seq(alloc, sizes, seq, index + 1); + } +} + +static void binder_selftest_alloc_size(struct binder_alloc *alloc, + size_t *end_offset) +{ + int i; + int seq[BUFFER_NUM] = {0}; + size_t front_sizes[BUFFER_NUM]; + size_t back_sizes[BUFFER_NUM]; + size_t last_offset, offset = 0; + + for (i = 0; i < BUFFER_NUM; i++) { + last_offset = offset; + offset = end_offset[i]; + front_sizes[i] = offset - last_offset; + back_sizes[BUFFER_NUM - i - 1] = front_sizes[i]; + } + /* + * Buffers share the first or last few pages. + * Only BUFFER_NUM - 1 buffer sizes are adjustable since + * we need one giant buffer before getting to the last page. + */ + back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; + binder_selftest_free_seq(alloc, front_sizes, seq, 0); + binder_selftest_free_seq(alloc, back_sizes, seq, 0); +} + +static void binder_selftest_alloc_offset(struct binder_alloc *alloc, + size_t *end_offset, int index) +{ + int align; + size_t end, prev; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_size(alloc, end_offset); + return; + } + prev = index == 0 ? 0 : end_offset[index - 1]; + end = prev; + + BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE); + + for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) { + if (align % 2) + end = ALIGN(end, PAGE_SIZE); + else + end += BUFFER_MIN_SIZE; + end_offset[index] = end; + binder_selftest_alloc_offset(alloc, end_offset, index + 1); + } +} + +/** + * binder_selftest_alloc() - Test alloc and free of buffer pages. + * @alloc: Pointer to alloc struct. + * + * Allocate BUFFER_NUM buffers to cover all page alignment cases, + * then free them in all orders possible. Check that pages are + * allocated after buffer alloc and freed after freeing buffer. + */ +void binder_selftest_alloc(struct binder_alloc *alloc) +{ + size_t end_offset[BUFFER_NUM]; + + if (!binder_selftest_run) + return; + mutex_lock(&binder_selftest_lock); + if (!binder_selftest_run || !alloc->vma) + goto done; + pr_info("STARTED\n"); + binder_selftest_alloc_offset(alloc, end_offset, 0); + binder_selftest_run = false; + if (binder_selftest_failures > 0) + pr_info("%d tests FAILED\n", binder_selftest_failures); + else + pr_info("PASSED\n"); + +done: + mutex_unlock(&binder_selftest_lock); +} diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..b908b55c5714d5e5ae7cab3e74d297a5c1914949 --- /dev/null +++ b/drivers/android/binder_internal.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_BINDER_INTERNAL_H +#define _LINUX_BINDER_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct binder_context { + struct binder_node *binder_context_mgr_node; + struct mutex context_mgr_node_lock; + kuid_t binder_context_mgr_uid; + const char *name; +}; + +/** + * struct binder_device - information about a binder device node + * @hlist: list of binder devices (only used for devices requested via + * CONFIG_ANDROID_BINDER_DEVICES) + * @miscdev: information about a binder character device node + * @context: binder context information + * @binderfs_inode: This is the inode of the root dentry of the super block + * belonging to a binderfs mount. + */ +struct binder_device { + struct hlist_node hlist; + struct miscdevice miscdev; + struct binder_context context; + struct inode *binderfs_inode; + refcount_t ref; +}; + +/** + * binderfs_mount_opts - mount options for binderfs + * @max: maximum number of allocatable binderfs binder devices + * @stats_mode: enable binder stats in binderfs. + */ +struct binderfs_mount_opts { + int max; + int stats_mode; +}; + +/** + * binderfs_info - information about a binderfs mount + * @ipc_ns: The ipc namespace the binderfs mount belongs to. + * @control_dentry: This records the dentry of this binderfs mount + * binder-control device. + * @root_uid: uid that needs to be used when a new binder device is + * created. + * @root_gid: gid that needs to be used when a new binder device is + * created. + * @mount_opts: The mount options in use. + * @device_count: The current number of allocated binder devices. + * @proc_log_dir: Pointer to the directory dentry containing process-specific + * logs. + */ +struct binderfs_info { + struct ipc_namespace *ipc_ns; + struct dentry *control_dentry; + kuid_t root_uid; + kgid_t root_gid; + struct binderfs_mount_opts mount_opts; + int device_count; + struct dentry *proc_log_dir; +}; + +extern const struct file_operations binder_fops; + +#ifdef CONFIG_ANDROID_BINDERFS +extern bool is_binderfs_device(const struct inode *inode); +extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name, + const struct file_operations *fops, + void *data); +extern void binderfs_remove_file(struct dentry *dentry); +#else +static inline bool is_binderfs_device(const struct inode *inode) +{ + return false; +} +static inline struct dentry *binderfs_create_file(struct dentry *dir, + const char *name, + const struct file_operations *fops, + void *data) +{ + return NULL; +} +static inline void binderfs_remove_file(struct dentry *dentry) {} +#endif + +#ifdef CONFIG_ANDROID_BINDERFS +extern int __init init_binderfs(void); +#else +static inline int __init init_binderfs(void) +{ + return 0; +} +#endif + +int binder_stats_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_stats); + +int binder_state_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_state); + +int binder_transactions_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transactions); + +int binder_transaction_log_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transaction_log); + +struct binder_transaction_log_entry { + int debug_id; + int debug_id_done; + int call_type; + int from_proc; + int from_thread; + int target_handle; + int to_proc; + int to_thread; + int to_node; + int data_size; + int offsets_size; + int return_error_line; + uint32_t return_error; + uint32_t return_error_param; + const char *context_name; +}; + +struct binder_transaction_log { + atomic_t cur; + bool full; + struct binder_transaction_log_entry entry[32]; +}; + +extern struct binder_transaction_log binder_transaction_log; +extern struct binder_transaction_log binder_transaction_log_failed; +#endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 7f20f3dc83690cad36cfa82c2a946384a8c30bb8..ef9f4baef02c7004867f74dcf0fa8b94fa72e8f0 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (C) 2012 Google, Inc. * * This software is licensed under the terms of the GNU General Public @@ -23,7 +23,8 @@ struct binder_buffer; struct binder_node; struct binder_proc; -struct binder_ref; +struct binder_alloc; +struct binder_ref_data; struct binder_thread; struct binder_transaction; @@ -84,6 +85,30 @@ DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done); DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done); DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done); +TRACE_EVENT(binder_set_priority, + TP_PROTO(int proc, int thread, unsigned int old_prio, + unsigned int desired_prio, unsigned int new_prio), + TP_ARGS(proc, thread, old_prio, new_prio, desired_prio), + + TP_STRUCT__entry( + __field(int, proc) + __field(int, thread) + __field(unsigned int, old_prio) + __field(unsigned int, new_prio) + __field(unsigned int, desired_prio) + ), + TP_fast_assign( + __entry->proc = proc; + __entry->thread = thread; + __entry->old_prio = old_prio; + __entry->new_prio = new_prio; + __entry->desired_prio = desired_prio; + ), + TP_printk("proc=%d thread=%d old=%d => new=%d desired=%d", + __entry->proc, __entry->thread, __entry->old_prio, + __entry->new_prio, __entry->desired_prio) +); + TRACE_EVENT(binder_wait_for_work, TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), TP_ARGS(proc_work, transaction_stack, thread_todo), @@ -146,8 +171,8 @@ TRACE_EVENT(binder_transaction_received, TRACE_EVENT(binder_transaction_node_to_ref, TP_PROTO(struct binder_transaction *t, struct binder_node *node, - struct binder_ref *ref), - TP_ARGS(t, node, ref), + struct binder_ref_data *rdata), + TP_ARGS(t, node, rdata), TP_STRUCT__entry( __field(int, debug_id) @@ -160,8 +185,8 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->debug_id = t->debug_id; __entry->node_debug_id = node->debug_id; __entry->node_ptr = node->ptr; - __entry->ref_debug_id = ref->debug_id; - __entry->ref_desc = ref->desc; + __entry->ref_debug_id = rdata->debug_id; + __entry->ref_desc = rdata->desc; ), TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", __entry->debug_id, __entry->node_debug_id, @@ -170,8 +195,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, ); TRACE_EVENT(binder_transaction_ref_to_node, - TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), - TP_ARGS(t, ref), + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref_data *rdata), + TP_ARGS(t, node, rdata), TP_STRUCT__entry( __field(int, debug_id) @@ -182,10 +208,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->ref_debug_id = ref->debug_id; - __entry->ref_desc = ref->desc; - __entry->node_debug_id = ref->node->debug_id; - __entry->node_ptr = ref->node->ptr; + __entry->ref_debug_id = rdata->debug_id; + __entry->ref_desc = rdata->desc; + __entry->node_debug_id = node->debug_id; + __entry->node_ptr = node->ptr; ), TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, @@ -194,9 +220,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ); TRACE_EVENT(binder_transaction_ref_to_ref, - TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, - struct binder_ref *dest_ref), - TP_ARGS(t, src_ref, dest_ref), + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref_data *src_ref, + struct binder_ref_data *dest_ref), + TP_ARGS(t, node, src_ref, dest_ref), TP_STRUCT__entry( __field(int, debug_id) @@ -208,7 +235,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->node_debug_id = src_ref->node->debug_id; + __entry->node_debug_id = node->debug_id; __entry->src_ref_debug_id = src_ref->debug_id; __entry->src_ref_desc = src_ref->desc; __entry->dest_ref_debug_id = dest_ref->debug_id; @@ -245,14 +272,17 @@ DECLARE_EVENT_CLASS(binder_buffer_class, __field(int, debug_id) __field(size_t, data_size) __field(size_t, offsets_size) + __field(size_t, extra_buffers_size) ), TP_fast_assign( __entry->debug_id = buf->debug_id; __entry->data_size = buf->data_size; __entry->offsets_size = buf->offsets_size; + __entry->extra_buffers_size = buf->extra_buffers_size; ), - TP_printk("transaction=%d data_size=%zd offsets_size=%zd", - __entry->debug_id, __entry->data_size, __entry->offsets_size) + TP_printk("transaction=%d data_size=%zd offsets_size=%zd extra_buffers_size=%zd", + __entry->debug_id, __entry->data_size, __entry->offsets_size, + __entry->extra_buffers_size) ); DEFINE_EVENT(binder_buffer_class, binder_transaction_alloc_buf, @@ -268,9 +298,9 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, TP_ARGS(buffer)); TRACE_EVENT(binder_update_page_range, - TP_PROTO(struct binder_proc *proc, bool allocate, + TP_PROTO(struct binder_alloc *alloc, bool allocate, void *start, void *end), - TP_ARGS(proc, allocate, start, end), + TP_ARGS(alloc, allocate, start, end), TP_STRUCT__entry( __field(int, proc) __field(bool, allocate) @@ -278,9 +308,9 @@ TRACE_EVENT(binder_update_page_range, __field(size_t, size) ), TP_fast_assign( - __entry->proc = proc->pid; + __entry->proc = alloc->pid; __entry->allocate = allocate; - __entry->offset = start - proc->buffer; + __entry->offset = start - alloc->buffer; __entry->size = end - start; ), TP_printk("proc=%d allocate=%d offset=%zu size=%zu", @@ -288,6 +318,61 @@ TRACE_EVENT(binder_update_page_range, __entry->offset, __entry->size) ); +DECLARE_EVENT_CLASS(binder_lru_page_class, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index), + TP_STRUCT__entry( + __field(int, proc) + __field(size_t, page_index) + ), + TP_fast_assign( + __entry->proc = alloc->pid; + __entry->page_index = page_index; + ), + TP_printk("proc=%d page_index=%zu", + __entry->proc, __entry->page_index) +); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + TRACE_EVENT(binder_command, TP_PROTO(uint32_t cmd), TP_ARGS(cmd), diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c new file mode 100644 index 0000000000000000000000000000000000000000..aeeb6feab5abbb15bc3054c8051786bd2d03c082 --- /dev/null +++ b/drivers/android/binderfs.c @@ -0,0 +1,796 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + +#include "binder_internal.h" + +#define FIRST_INODE 1 +#define SECOND_INODE 2 +#define INODE_OFFSET 3 +#define INTSTRLEN 21 +#define BINDERFS_MAX_MINOR (1U << MINORBITS) +/* Ensure that the initial ipc namespace always has devices available. */ +#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) + +static dev_t binderfs_dev; +static DEFINE_MUTEX(binderfs_minors_mutex); +static DEFINE_IDA(binderfs_minors); + +enum { + Opt_max, + Opt_stats_mode, + Opt_err +}; + +enum binderfs_stats_mode { + STATS_NONE, + STATS_GLOBAL, +}; + +static const match_table_t tokens = { + { Opt_max, "max=%d" }, + { Opt_stats_mode, "stats=%s" }, + { Opt_err, NULL } +}; + +static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) +{ + return inode->i_sb->s_fs_info; +} + +bool is_binderfs_device(const struct inode *inode) +{ + if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC) + return true; + + return false; +} + +/** + * binderfs_binder_device_create - allocate inode from super block of a + * binderfs mount + * @ref_inode: inode from wich the super block will be taken + * @userp: buffer to copy information about new device for userspace to + * @req: struct binderfs_device as copied from userspace + * + * This function allocates a new binder_device and reserves a new minor + * number for it. + * Minor numbers are limited and tracked globally in binderfs_minors. The + * function will stash a struct binder_device for the specific binder + * device in i_private of the inode. + * It will go on to allocate a new inode from the super block of the + * filesystem mount, stash a struct binder_device in its i_private field + * and attach a dentry to that inode. + * + * Return: 0 on success, negative errno on failure + */ +static int binderfs_binder_device_create(struct inode *ref_inode, + struct binderfs_device __user *userp, + struct binderfs_device *req) +{ + int minor, ret; + struct dentry *dentry, *root; + struct binder_device *device; + char *name = NULL; + size_t name_len; + struct inode *inode = NULL; + struct super_block *sb = ref_inode->i_sb; + struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) + bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif + + /* Reserve new minor number for the new device. */ + mutex_lock(&binderfs_minors_mutex); + if (++info->device_count <= info->mount_opts.max) + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, + GFP_KERNEL); + else + minor = -ENOSPC; + if (minor < 0) { + --info->device_count; + mutex_unlock(&binderfs_minors_mutex); + return minor; + } + mutex_unlock(&binderfs_minors_mutex); + + ret = -ENOMEM; + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + goto err; + + inode = new_inode(sb); + if (!inode) + goto err; + + inode->i_ino = minor + INODE_OFFSET; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + init_special_inode(inode, S_IFCHR | 0600, + MKDEV(MAJOR(binderfs_dev), minor)); + inode->i_fop = &binder_fops; + inode->i_uid = info->root_uid; + inode->i_gid = info->root_gid; + + req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ + name_len = strlen(req->name); + /* Make sure to include terminating NUL byte */ + name = kmemdup(req->name, name_len + 1, GFP_KERNEL); + if (!name) + goto err; + + refcount_set(&device->ref, 1); + device->binderfs_inode = inode; + device->context.binder_context_mgr_uid = INVALID_UID; + device->context.name = name; + device->miscdev.name = name; + device->miscdev.minor = minor; + mutex_init(&device->context.context_mgr_node_lock); + + req->major = MAJOR(binderfs_dev); + req->minor = minor; + + ret = copy_to_user(userp, req, sizeof(*req)); + if (ret) { + ret = -EFAULT; + goto err; + } + + root = sb->s_root; + inode_lock(d_inode(root)); + + /* look it up */ + dentry = lookup_one_len(name, root, name_len); + if (IS_ERR(dentry)) { + inode_unlock(d_inode(root)); + ret = PTR_ERR(dentry); + goto err; + } + + if (d_really_is_positive(dentry)) { + /* already exists */ + dput(dentry); + inode_unlock(d_inode(root)); + ret = -EEXIST; + goto err; + } + + inode->i_private = device; + d_instantiate(dentry, inode); + fsnotify_create(root->d_inode, dentry); + inode_unlock(d_inode(root)); + + return 0; + +err: + kfree(name); + kfree(device); + mutex_lock(&binderfs_minors_mutex); + --info->device_count; + ida_free(&binderfs_minors, minor); + mutex_unlock(&binderfs_minors_mutex); + iput(inode); + + return ret; +} + +/** + * binderfs_ctl_ioctl - handle binder device node allocation requests + * + * The request handler for the binder-control device. All requests operate on + * the binderfs mount the binder-control device resides in: + * - BINDER_CTL_ADD + * Allocate a new binder device. + * + * Return: 0 on success, negative errno on failure + */ +static long binder_ctl_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -EINVAL; + struct inode *inode = file_inode(file); + struct binderfs_device __user *device = (struct binderfs_device __user *)arg; + struct binderfs_device device_req; + + switch (cmd) { + case BINDER_CTL_ADD: + ret = copy_from_user(&device_req, device, sizeof(device_req)); + if (ret) { + ret = -EFAULT; + break; + } + + ret = binderfs_binder_device_create(inode, device, &device_req); + break; + default: + break; + } + + return ret; +} + +static void binderfs_evict_inode(struct inode *inode) +{ + struct binder_device *device = inode->i_private; + struct binderfs_info *info = BINDERFS_I(inode); + + clear_inode(inode); + + if (!S_ISCHR(inode->i_mode) || !device) + return; + + mutex_lock(&binderfs_minors_mutex); + --info->device_count; + ida_free(&binderfs_minors, device->miscdev.minor); + mutex_unlock(&binderfs_minors_mutex); + + if (refcount_dec_and_test(&device->ref)) { + kfree(device->context.name); + kfree(device); + } +} + +/** + * binderfs_parse_mount_opts - parse binderfs mount options + * @data: options to set (can be NULL in which case defaults are used) + */ +static int binderfs_parse_mount_opts(char *data, + struct binderfs_mount_opts *opts) +{ + char *p, *stats; + opts->max = BINDERFS_MAX_MINOR; + opts->stats_mode = STATS_NONE; + + while ((p = strsep(&data, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + int max_devices; + + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_max: + if (match_int(&args[0], &max_devices) || + (max_devices < 0 || + (max_devices > BINDERFS_MAX_MINOR))) + return -EINVAL; + + opts->max = max_devices; + break; + case Opt_stats_mode: + if (!capable(CAP_SYS_ADMIN)) + return -EINVAL; + + stats = match_strdup(&args[0]); + if (!stats) + return -ENOMEM; + + if (strcmp(stats, "global") != 0) { + kfree(stats); + return -EINVAL; + } + + opts->stats_mode = STATS_GLOBAL; + kfree(stats); + break; + default: + pr_err("Invalid mount options\n"); + return -EINVAL; + } + } + + return 0; +} + +static int binderfs_remount(struct super_block *sb, int *flags, char *data) +{ + int prev_stats_mode, ret; + struct binderfs_info *info = sb->s_fs_info; + + prev_stats_mode = info->mount_opts.stats_mode; + ret = binderfs_parse_mount_opts(data, &info->mount_opts); + if (ret) + return ret; + + if (prev_stats_mode != info->mount_opts.stats_mode) { + pr_err("Binderfs stats mode cannot be changed during a remount\n"); + info->mount_opts.stats_mode = prev_stats_mode; + return -EINVAL; + } + + return 0; +} + +static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) +{ + struct binderfs_info *info; + + info = root->d_sb->s_fs_info; + if (info->mount_opts.max <= BINDERFS_MAX_MINOR) + seq_printf(seq, ",max=%d", info->mount_opts.max); + if (info->mount_opts.stats_mode == STATS_GLOBAL) + seq_printf(seq, ",stats=global"); + + return 0; +} + +static const struct super_operations binderfs_super_ops = { + .evict_inode = binderfs_evict_inode, + .remount_fs = binderfs_remount, + .show_options = binderfs_show_mount_opts, + .statfs = simple_statfs, +}; + +static inline bool is_binderfs_control_device(const struct dentry *dentry) +{ + struct binderfs_info *info = dentry->d_sb->s_fs_info; + + return info->control_dentry == dentry; +} + +static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + if (is_binderfs_control_device(old_dentry) || + is_binderfs_control_device(new_dentry)) + return -EPERM; + + return simple_rename(old_dir, old_dentry, new_dir, new_dentry, flags); +} + +static int binderfs_unlink(struct inode *dir, struct dentry *dentry) +{ + if (is_binderfs_control_device(dentry)) + return -EPERM; + + return simple_unlink(dir, dentry); +} + +static const struct file_operations binder_ctl_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .unlocked_ioctl = binder_ctl_ioctl, + .compat_ioctl = binder_ctl_ioctl, + .llseek = noop_llseek, +}; + +/** + * binderfs_binder_ctl_create - create a new binder-control device + * @sb: super block of the binderfs mount + * + * This function creates a new binder-control device node in the binderfs mount + * referred to by @sb. + * + * Return: 0 on success, negative errno on failure + */ +static int binderfs_binder_ctl_create(struct super_block *sb) +{ + int minor, ret; + struct dentry *dentry; + struct binder_device *device; + struct inode *inode = NULL; + struct dentry *root = sb->s_root; + struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) + bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif + + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + return -ENOMEM; + + /* If we have already created a binder-control node, return. */ + if (info->control_dentry) { + ret = 0; + goto out; + } + + ret = -ENOMEM; + inode = new_inode(sb); + if (!inode) + goto out; + + /* Reserve a new minor number for the new device. */ + mutex_lock(&binderfs_minors_mutex); + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, + GFP_KERNEL); + mutex_unlock(&binderfs_minors_mutex); + if (minor < 0) { + ret = minor; + goto out; + } + + inode->i_ino = SECOND_INODE; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + init_special_inode(inode, S_IFCHR | 0600, + MKDEV(MAJOR(binderfs_dev), minor)); + inode->i_fop = &binder_ctl_fops; + inode->i_uid = info->root_uid; + inode->i_gid = info->root_gid; + + refcount_set(&device->ref, 1); + device->binderfs_inode = inode; + device->miscdev.minor = minor; + + dentry = d_alloc_name(root, "binder-control"); + if (!dentry) + goto out; + + inode->i_private = device; + info->control_dentry = dentry; + d_add(dentry, inode); + + return 0; + +out: + kfree(device); + iput(inode); + + return ret; +} + +static const struct inode_operations binderfs_dir_inode_operations = { + .lookup = simple_lookup, + .rename = binderfs_rename, + .unlink = binderfs_unlink, +}; + +static struct inode *binderfs_make_inode(struct super_block *sb, int mode) +{ + struct inode *ret; + + ret = new_inode(sb); + if (ret) { + ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); + ret->i_mode = mode; + ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret); + } + return ret; +} + +static struct dentry *binderfs_create_dentry(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) + return dentry; + + /* Return error if the file/dir already exists. */ + if (d_really_is_positive(dentry)) { + dput(dentry); + return ERR_PTR(-EEXIST); + } + + return dentry; +} + +void binderfs_remove_file(struct dentry *dentry) +{ + struct inode *parent_inode; + + parent_inode = d_inode(dentry->d_parent); + inode_lock(parent_inode); + if (simple_positive(dentry)) { + dget(dentry); + simple_unlink(parent_inode, dentry); + d_delete(dentry); + dput(dentry); + } + inode_unlock(parent_inode); +} + +struct dentry *binderfs_create_file(struct dentry *parent, const char *name, + const struct file_operations *fops, + void *data) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFREG | 0444); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = fops; + new_inode->i_private = data; + d_instantiate(dentry, new_inode); + fsnotify_create(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static struct dentry *binderfs_create_dir(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = &simple_dir_operations; + new_inode->i_op = &simple_dir_inode_operations; + + set_nlink(new_inode, 2); + d_instantiate(dentry, new_inode); + inc_nlink(parent_inode); + fsnotify_mkdir(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static int init_binder_logs(struct super_block *sb) +{ + struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; + struct binderfs_info *info; + int ret = 0; + + binder_logs_root_dir = binderfs_create_dir(sb->s_root, + "binder_logs"); + if (IS_ERR(binder_logs_root_dir)) { + ret = PTR_ERR(binder_logs_root_dir); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "stats", + &binder_stats_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "state", + &binder_state_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "transactions", + &binder_transactions_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, + "transaction_log", + &binder_transaction_log_fops, + &binder_transaction_log); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, + "failed_transaction_log", + &binder_transaction_log_fops, + &binder_transaction_log_failed); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); + if (IS_ERR(proc_log_dir)) { + ret = PTR_ERR(proc_log_dir); + goto out; + } + info = sb->s_fs_info; + info->proc_log_dir = proc_log_dir; + +out: + return ret; +} + +static int binderfs_fill_super(struct super_block *sb, void *data, int silent) +{ + int ret; + struct binderfs_info *info; + struct inode *inode = NULL; + struct binderfs_device device_info = {}; + + sb->s_blocksize = PAGE_SIZE; + sb->s_blocksize_bits = PAGE_SHIFT; + + /* + * The binderfs filesystem can be mounted by userns root in a + * non-initial userns. By default such mounts have the SB_I_NODEV flag + * set in s_iflags to prevent security issues where userns root can + * just create random device nodes via mknod() since it owns the + * filesystem mount. But binderfs does not allow to create any files + * including devices nodes. The only way to create binder devices nodes + * is through the binder-control device which userns root is explicitly + * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both + * necessary and safe. + */ + sb->s_iflags &= ~SB_I_NODEV; + sb->s_iflags |= SB_I_NOEXEC; + sb->s_magic = BINDERFS_SUPER_MAGIC; + sb->s_op = &binderfs_super_ops; + sb->s_time_gran = 1; + + sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); + if (!sb->s_fs_info) + return -ENOMEM; + info = sb->s_fs_info; + + info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); + + ret = binderfs_parse_mount_opts(data, &info->mount_opts); + if (ret) + return ret; + + info->root_gid = make_kgid(sb->s_user_ns, 0); + if (!gid_valid(info->root_gid)) + info->root_gid = GLOBAL_ROOT_GID; + info->root_uid = make_kuid(sb->s_user_ns, 0); + if (!uid_valid(info->root_uid)) + info->root_uid = GLOBAL_ROOT_UID; + + inode = new_inode(sb); + if (!inode) + return -ENOMEM; + + inode->i_ino = FIRST_INODE; + inode->i_fop = &simple_dir_operations; + inode->i_mode = S_IFDIR | 0755; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_op = &binderfs_dir_inode_operations; + set_nlink(inode, 2); + + sb->s_root = d_make_root(inode); + if (!sb->s_root) + return -ENOMEM; + + ret = binderfs_binder_ctl_create(sb); + if (ret) + return ret; + + name = binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + strscpy(device_info.name, name, len + 1); + ret = binderfs_binder_device_create(inode, NULL, &device_info); + if (ret) + return ret; + name += len; + if (*name == ',') + name++; + } + + if (info->mount_opts.stats_mode == STATS_GLOBAL) + return init_binder_logs(sb); + + return 0; +} + +static struct dentry *binderfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + return mount_nodev(fs_type, flags, data, binderfs_fill_super); +} + +static void binderfs_kill_super(struct super_block *sb) +{ + struct binderfs_info *info = sb->s_fs_info; + + kill_litter_super(sb); + + if (info && info->ipc_ns) + put_ipc_ns(info->ipc_ns); + + kfree(info); +} + +static struct file_system_type binder_fs_type = { + .name = "binder", + .mount = binderfs_mount, + .kill_sb = binderfs_kill_super, + .fs_flags = FS_USERNS_MOUNT, +}; + +static int __init init_binderfs(void) +{ + int ret; + const char *name; + size_t len; + + /* Verify that the default binderfs device names are valid. */ + name = binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + if (len > BINDERFS_MAX_NAME) + return -E2BIG; + name += len; + if (*name == ',') + name++; + } + + /* Allocate new major number for binderfs. */ + ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, + "binder"); + if (ret) + return ret; + + ret = register_filesystem(&binder_fs_type); + if (ret) { + unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); + return ret; + } + + return ret; +} + +device_initcall(init_binderfs); diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 815d822565a7fd0e4c8ef98c08c10066fc831cfb..e08f4c6d65f56546bd43aae4b16d89e082d23ff1 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2018 The Linux Foundation. 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 and @@ -62,6 +62,9 @@ up_read(¤t->mm->mmap_sem);\ } while (0) +#define FASTRPC_CTX_MAGIC (0xbeeddeed) +#define FASTRPC_CTX_MAX (256) +#define FASTRPC_CTXID_MASK (0xFF0) #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) @@ -77,7 +80,7 @@ static inline uintptr_t buf_page_offset(void *buf) return offset; } -static inline int buf_num_pages(void *buf, ssize_t len) +static inline int buf_num_pages(void *buf, size_t len) { uintptr_t start = buf_page_start(buf) >> PAGE_SHIFT; uintptr_t end = (((uintptr_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT; @@ -91,6 +94,13 @@ static inline uint32_t buf_page_size(uint32_t size) return sz > PAGE_SIZE ? sz : PAGE_SIZE; } +static inline uint64_t ptr_to_uint64(void *ptr) +{ + uint64_t addr = (uint64_t)((uintptr_t)ptr); + + return addr; +} + static inline int buf_get_pages(void *addr, ssize_t sz, int nr_pages, int access, struct smq_phy_page *pages, int nr_elems, struct smq_phy_page *range) @@ -142,7 +152,7 @@ struct fastrpc_buf { struct ion_handle *handle; void *virt; ion_phys_addr_t phys; - ssize_t size; + size_t size; int used; }; @@ -178,6 +188,8 @@ struct smq_invoke_ctx { uint32_t sc; struct overlap *overs; struct overlap **overps; + unsigned int magic; + uint64_t ctxid; }; struct smq_context_list { @@ -216,6 +228,8 @@ struct fastrpc_apps { spinlock_t wrlock; spinlock_t hlock; struct hlist_head htbl[RPC_HASH_SZ]; + spinlock_t ctxlock; + struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX]; }; struct fastrpc_mmap { @@ -225,7 +239,7 @@ struct fastrpc_mmap { ion_phys_addr_t phys; uintptr_t *vaddrin; uintptr_t vaddrout; - ssize_t size; + size_t size; int refs; }; @@ -273,7 +287,7 @@ static int map_iommu_mem(struct ion_handle *handle, struct file_data *fdata, ion_phys_addr_t *iova, unsigned long size) { struct fastrpc_apps *me = &gfa; - struct fastrpc_mmap *map = 0, *mapmatch = 0; + struct fastrpc_mmap *map = NULL, *mapmatch = NULL; struct hlist_node *n; unsigned long len = size; int cid = fdata->cid; @@ -307,7 +321,7 @@ static void unmap_iommu_mem(struct ion_handle *handle, struct file_data *fdata, int cached) { struct fastrpc_apps *me = &gfa; - struct fastrpc_mmap *map = 0, *mapmatch = 0; + struct fastrpc_mmap *map = NULL, *mapmatch = NULL; struct hlist_node *n; int cid = fdata->cid; @@ -342,10 +356,10 @@ static void free_mem(struct fastrpc_buf *buf, struct file_data *fd) } if (!IS_ERR_OR_NULL(buf->virt)) { ion_unmap_kernel(me->iclient, buf->handle); - buf->virt = 0; + buf->virt = NULL; } ion_free(me->iclient, buf->handle); - buf->handle = 0; + buf->handle = NULL; } } @@ -361,11 +375,11 @@ static void free_map(struct fastrpc_mmap *map, struct file_data *fdata) } if (!IS_ERR_OR_NULL(map->virt)) { ion_unmap_kernel(me->iclient, map->handle); - map->virt = 0; + map->virt = NULL; } ion_free(me->iclient, map->handle); } - map->handle = 0; + map->handle = NULL; } static int alloc_mem(struct fastrpc_buf *buf, struct file_data *fdata) @@ -376,8 +390,8 @@ static int alloc_mem(struct fastrpc_buf *buf, struct file_data *fdata) int err = 0; int cid = fdata->cid; unsigned int heap; - buf->handle = 0; - buf->virt = 0; + buf->handle = NULL; + buf->virt = NULL; buf->phys = 0; heap = me->channel[cid].smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) : ION_HEAP(ION_ADSP_HEAP_ID); @@ -412,7 +426,7 @@ static int context_restore_interrupted(struct fastrpc_apps *me, struct smq_invoke_ctx **po) { int err = 0; - struct smq_invoke_ctx *ctx = 0, *ictx = 0; + struct smq_invoke_ctx *ctx = NULL, *ictx = NULL; struct hlist_node *n; struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; spin_lock(&me->clst.hlock); @@ -507,9 +521,10 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, struct file_data *fdata, struct smq_invoke_ctx **po) { - int err = 0, bufs, size = 0; - struct smq_invoke_ctx *ctx = 0; + int err = 0, bufs, ii, size = 0; + struct smq_invoke_ctx *ctx = NULL; struct smq_context_list *clst = &me->clst; + struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; bufs = REMOTE_SCALARS_INBUFS(invoke->sc) + @@ -521,7 +536,7 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, bufs * sizeof(*ctx->handles); } - VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL))); + VERIFY(err, NULL != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL))); if (err) goto bail; @@ -530,8 +545,8 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, ctx->apps = me; ctx->fdata = fdata; ctx->pra = (remote_arg_t *)(&ctx[1]); - ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]); - ctx->handles = invokefd->fds == 0 ? 0 : + ctx->fds = invokefd->fds == NULL ? NULL : (int *)(&ctx->pra[bufs]); + ctx->handles = invokefd->fds == NULL ? NULL : (struct ion_handle **)(&ctx->fds[bufs]); if (!kernel) { VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra, @@ -563,10 +578,26 @@ static int context_alloc(struct fastrpc_apps *me, uint32_t kernel, ctx->pid = current->pid; ctx->tgid = current->tgid; init_completion(&ctx->work); + ctx->magic = FASTRPC_CTX_MAGIC; spin_lock(&clst->hlock); hlist_add_head(&ctx->hn, &clst->pending); spin_unlock(&clst->hlock); + spin_lock(&me->ctxlock); + for (ii = 0; ii < FASTRPC_CTX_MAX; ii++) { + if (!me->ctxtable[ii]) { + me->ctxtable[ii] = ctx; + ctx->ctxid = (ptr_to_uint64(ctx) & ~0xFFF)|(ii << 4); + break; + } + } + spin_unlock(&me->ctxlock); + VERIFY(err, ii < FASTRPC_CTX_MAX); + if (err) { + pr_err("adsprpc: out of context memory\n"); + goto bail; + } + *po = ctx; bail: if (ctx && err) @@ -594,6 +625,7 @@ static void context_free(struct smq_invoke_ctx *ctx, int remove) int ssrcount = ctx->fdata->ssrcount; struct fastrpc_smmu *smmu = &apps->channel[cid].smmu; struct fastrpc_buf *b; + struct fastrpc_apps *me = &gfa; int i, bufs; if (ctx->smmu) { bufs = REMOTE_SCALARS_INBUFS(ctx->sc) + @@ -615,6 +647,17 @@ static void context_free(struct smq_invoke_ctx *ctx, int remove) free_mem(b, ctx->fdata); kfree(ctx->abufs); + ctx->magic = 0; + ctx->ctxid = 0; + + spin_lock(&me->ctxlock); + for (i = 0; i < FASTRPC_CTX_MAX; i++) { + if (me->ctxtable[i] == ctx) { + me->ctxtable[i] = NULL; + break; + } + } + spin_unlock(&me->ctxlock); if (ctx->dev) { add_dev(apps, ctx->dev); if (ctx->obuf.handle != ctx->dev->buf.handle) @@ -638,7 +681,7 @@ static void context_notify_user(struct smq_invoke_ctx *ctx, int retval) static void context_notify_all_users(struct smq_context_list *me, int cid) { - struct smq_invoke_ctx *ictx = 0; + struct smq_invoke_ctx *ictx = NULL; struct hlist_node *n; spin_lock(&me->hlock); hlist_for_each_entry_safe(ictx, n, &me->pending, hn) { @@ -663,10 +706,10 @@ static void context_list_ctor(struct smq_context_list *me) static void context_list_dtor(struct fastrpc_apps *me, struct smq_context_list *clst) { - struct smq_invoke_ctx *ictx = 0, *ctxfree; + struct smq_invoke_ctx *ictx = NULL, *ctxfree; struct hlist_node *n; do { - ctxfree = 0; + ctxfree = NULL; spin_lock(&clst->hlock); hlist_for_each_entry_safe(ictx, n, &clst->interrupted, hn) { hlist_del(&ictx->hn); @@ -699,7 +742,7 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx) struct fastrpc_buf *ibuf = &ctx->dev->buf; struct fastrpc_buf *obuf = &ctx->obuf; remote_arg_t *pra = ctx->pra; - ssize_t rlen; + size_t rlen; uint32_t sc = ctx->sc; int cid = ctx->fdata->cid; int i, err = 0; @@ -726,7 +769,7 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx) for (i = 0; i < inbufs + outbufs; ++i) { void *buf; int num; - ssize_t len; + size_t len; list[i].num = 0; list[i].pgidx = 0; @@ -833,14 +876,14 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx, { struct fastrpc_apps *me = &gfa; struct smq_invoke_buf *list; - struct fastrpc_buf *pbuf = &ctx->obuf, *obufs = 0; + struct fastrpc_buf *pbuf = &ctx->obuf, *obufs = NULL; struct smq_phy_page *pages; struct vm_area_struct *vma; struct ion_handle **handles = ctx->handles; void *args; remote_arg_t *pra = ctx->pra; remote_arg_t *rpra = ctx->rpra; - ssize_t rlen, used, size, copylen = 0; + size_t rlen, used, size, copylen = 0; uint32_t sc = ctx->sc, start; int i, inh, bufs = 0, err = 0, oix; int inbufs = REMOTE_SCALARS_INBUFS(sc); @@ -933,7 +976,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx, /* copy non ion buffers */ for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; - ssize_t mlen = ctx->overps[oix]->mend - ctx->overps[oix]->mstart; + size_t mlen = ctx->overps[oix]->mend - ctx->overps[oix]->mstart; if (!pra[i].buf.len) continue; if (list[i].num) @@ -1093,7 +1136,7 @@ static int fastrpc_invoke_send(struct fastrpc_apps *me, msg.tid = current->pid; if (kernel) msg.pid = 0; - msg.invoke.header.ctx = ctx; + msg.invoke.header.ctx = ctx->ctxid; msg.invoke.header.handle = handle; msg.invoke.header.sc = sc; msg.invoke.page.addr = buf->phys; @@ -1123,16 +1166,35 @@ static void fastrpc_deinit(void) static void fastrpc_read_handler(int cid) { struct fastrpc_apps *me = &gfa; - struct smq_invoke_rsp rsp; - int ret = 0; + struct smq_invoke_rsp rsp = {0}; + int ret = 0, err = 0; + uint32_t index; do { ret = smd_read_from_cb(me->channel[cid].chan, &rsp, sizeof(rsp)); if (ret != sizeof(rsp)) break; - context_notify_user(rsp.ctx, rsp.retval); + index = (uint32_t)((rsp.ctx & FASTRPC_CTXID_MASK) >> 4); + VERIFY(err, index < FASTRPC_CTX_MAX); + if (err) + goto bail; + + VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index])); + if (err) + goto bail; + + VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp.ctx)) && + me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC)); + if (err) + goto bail; + + context_notify_user(me->ctxtable[index], rsp.retval); } while (ret == sizeof(rsp)); + +bail: + if (err) + pr_err("adsprpc: invalid response or context\n"); } static void smd_event_handler(void *priv, unsigned event) @@ -1163,6 +1225,7 @@ static int fastrpc_init(void) spin_lock_init(&me->hlock); spin_lock_init(&me->wrlock); + spin_lock_init(&me->ctxlock); mutex_init(&me->smd_mutex); context_list_ctor(&me->clst); for (i = 0; i < RPC_HASH_SZ; ++i) @@ -1208,7 +1271,7 @@ static void free_dev(struct fastrpc_device *dev, struct file_data *fdata) static int alloc_dev(struct fastrpc_device **dev, struct file_data *fdata) { int err = 0; - struct fastrpc_device *fd = 0; + struct fastrpc_device *fd = NULL; VERIFY(err, 0 != try_module_get(THIS_MODULE)); if (err) @@ -1236,7 +1299,7 @@ static int get_dev(struct fastrpc_apps *me, struct file_data *fdata, struct fastrpc_device **rdev) { struct hlist_head *head; - struct fastrpc_device *dev = 0, *devfree = 0; + struct fastrpc_device *dev = NULL, *devfree = NULL; struct hlist_node *n; uint32_t h = hash_32(current->tgid, RPC_HASH_BITS); int err = 0; @@ -1282,7 +1345,7 @@ static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode, struct fastrpc_ioctl_invoke_fd *invokefd, struct file_data *fdata) { - struct smq_invoke_ctx *ctx = 0; + struct smq_invoke_ctx *ctx = NULL; struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; int cid = fdata->cid; int interrupted = 0; @@ -1371,8 +1434,8 @@ static int fastrpc_init_process(struct file_data *fdata, { int err = 0; struct fastrpc_ioctl_invoke_fd ioctl; - struct smq_phy_page *pages = 0; - struct fastrpc_mmap *map = 0; + struct smq_phy_page *pages = NULL; + struct fastrpc_mmap *map = NULL; int npages = 0; struct fastrpc_apps *me = &gfa; if (init->flags == FASTRPC_INIT_ATTACH) { @@ -1400,6 +1463,12 @@ static int fastrpc_init_process(struct file_data *fdata, inbuf.pgid = current->tgid; inbuf.namelen = strlen(current->comm); inbuf.filelen = init->filelen; + if (!access_ok(0, (void const __user *)init->file, + init->filelen)) + goto bail; + if (!access_ok(1, (void const __user *)init->mem, + init->memlen)) + goto bail; VERIFY(err, 0 == map_buffer(me, fdata, init->memfd, (char *)init->mem, init->memlen, &map, &pages, &npages)); @@ -1521,7 +1590,7 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me, struct { int pid; uintptr_t vaddrout; - ssize_t size; + size_t size; } inargs; inargs.pid = current->tgid; @@ -1575,9 +1644,9 @@ static int map_buffer(struct fastrpc_apps *me, struct file_data *fdata, struct smq_phy_page **ppages, int *pnpages) { struct ion_client *clnt = gfa.iclient; - struct ion_handle *handle = 0; - struct fastrpc_mmap *map = 0, *mapmatch = 0; - struct smq_phy_page *pages = 0; + struct ion_handle *handle = NULL; + struct fastrpc_mmap *map = NULL, *mapmatch = NULL; + struct smq_phy_page *pages = NULL; struct hlist_node *n; uintptr_t vaddrout = 0; int num; @@ -1654,8 +1723,8 @@ static int fastrpc_internal_mmap(struct fastrpc_apps *me, struct fastrpc_ioctl_mmap *mmap) { - struct fastrpc_mmap *map = 0; - struct smq_phy_page *pages = 0; + struct fastrpc_mmap *map = NULL; + struct smq_phy_page *pages = NULL; int num = 0; int err = 0; VERIFY(err, 0 == map_buffer(me, fdata, mmap->fd, (char *)mmap->vaddrin, @@ -1685,7 +1754,7 @@ static void cleanup_current_dev(struct file_data *fdata) struct fastrpc_device *dev, *devfree; rnext: - devfree = dev = 0; + devfree = dev = NULL; spin_lock(&me->hlock); head = &me->htbl[h]; hlist_for_each_entry_safe(dev, n, head, hn) { @@ -1723,9 +1792,9 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) struct file_data *fdata = (struct file_data *)file->private_data; struct fastrpc_apps *me = &gfa; struct smq_context_list *clst = &me->clst; - struct smq_invoke_ctx *ictx = 0, *ctxfree; + struct smq_invoke_ctx *ictx = NULL, *ctxfree; struct hlist_node *n; - struct fastrpc_mmap *map = 0; + struct fastrpc_mmap *map = NULL; int cid = MINOR(inode->i_rdev); if (!fdata) @@ -1733,7 +1802,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) (void)fastrpc_release_current_dsp_process(fdata); do { - ctxfree = 0; + ctxfree = NULL; spin_lock(&clst->hlock); hlist_for_each_entry_safe(ictx, n, &clst->interrupted, hn) { if ((ictx->tgid == current->tgid) && @@ -1771,7 +1840,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) mutex_lock(&me->smd_mutex); ssrcount = me->channel[cid].ssrcount; if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || - (me->channel[cid].chan == 0)) { + (me->channel[cid].chan == NULL)) { VERIFY(err, 0 == smd_named_open_on_edge( FASTRPC_SMD_GUID, gcinfo[cid].channel, @@ -1791,9 +1860,9 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) } mutex_unlock(&me->smd_mutex); - filp->private_data = 0; + filp->private_data = NULL; if (0 != try_module_get(THIS_MODULE)) { - struct file_data *fdata = 0; + struct file_data *fdata = NULL; /* This call will cause a dev to be created * which will addref this module */ @@ -1823,7 +1892,7 @@ bail: completion_bail: smd_close(me->channel[cid].chan); - me->channel[cid].chan = 0; + me->channel[cid].chan = NULL; smd_bail: mutex_unlock(&me->smd_mutex); return err; @@ -1845,7 +1914,7 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, switch (ioctl_num) { case FASTRPC_IOCTL_INVOKE_FD: case FASTRPC_IOCTL_INVOKE: - invokefd.fds = 0; + invokefd.fds = NULL; size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ? sizeof(invokefd.inv) : sizeof(invokefd); VERIFY(err, 0 == copy_from_user(&invokefd, param, size)); @@ -1923,7 +1992,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, ctx->ssrcount++; if (ctx->chan) { smd_close(ctx->chan); - ctx->chan = 0; + ctx->chan = NULL; pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); } diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c index ee324dcf91f0e3cb7861d6d44124852429b6da78..160ad1851c9a81a718aa3c5354d0a8addf9ddf72 100644 --- a/drivers/char/adsprpc_compat.c +++ b/drivers/char/adsprpc_compat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2017 The Linux Foundation. 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 and @@ -33,7 +33,7 @@ struct compat_remote_buf { compat_uptr_t pv; /* buffer pointer */ - compat_ssize_t len; /* length of buffer */ + compat_size_t len; /* length of buffer */ }; union compat_remote_arg { @@ -56,13 +56,13 @@ struct compat_fastrpc_ioctl_mmap { compat_int_t fd; /* ion fd */ compat_uint_t flags; /* flags for dsp to map with */ compat_uptr_t vaddrin; /* optional virtual address */ - compat_ssize_t size; /* size */ + compat_size_t size; /* size */ compat_uptr_t vaddrout; /* dsps virtual address */ }; struct compat_fastrpc_ioctl_munmap { compat_uptr_t vaddrout; /* address to unmap */ - compat_ssize_t size; /* size */ + compat_size_t size; /* size */ }; struct compat_fastrpc_ioctl_init { @@ -81,7 +81,7 @@ static int compat_get_fastrpc_ioctl_invoke( unsigned int cmd) { compat_uint_t u, sc; - compat_ssize_t s; + compat_size_t s; compat_uptr_t p; struct fastrpc_ioctl_invoke_fd *inv; union compat_remote_arg *pra32; @@ -164,7 +164,7 @@ static int compat_get_fastrpc_ioctl_mmap( { compat_uint_t u; compat_int_t i; - compat_ssize_t s; + compat_size_t s; compat_uptr_t p; int err; @@ -198,7 +198,7 @@ static int compat_get_fastrpc_ioctl_munmap( struct fastrpc_ioctl_munmap __user *unmap) { compat_uptr_t p; - compat_ssize_t s; + compat_size_t s; int err; err = get_user(p, &unmap32->vaddrout); diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index c0f8d3cc8c4e37d01f8ff09c6a951a8a90844735..b8e5f23a56c04767522e36b6b896906de173913f 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014,2017 The Linux Foundation. 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 and @@ -93,7 +93,7 @@ do {\ struct remote_buf { void *pv; /* buffer pointer */ - ssize_t len; /* length of buffer */ + size_t len; /* length of buffer */ }; union remote_arg { @@ -114,37 +114,37 @@ struct fastrpc_ioctl_invoke_fd { struct fastrpc_ioctl_init { uint32_t flags; /* one of FASTRPC_INIT_* macros */ - uintptr_t __user file; /* pointer to elf file */ - int32_t filelen; /* elf file length */ + uintptr_t file; /* pointer to elf file */ + uint32_t filelen; /* elf file length */ int32_t filefd; /* ION fd for the file */ - uintptr_t __user mem; /* mem for the PD */ - int32_t memlen; /* mem length */ + uintptr_t mem; /* mem for the PD */ + uint32_t memlen; /* mem length */ int32_t memfd; /* ION fd for the mem */ }; struct fastrpc_ioctl_munmap { uintptr_t vaddrout; /* address to unmap */ - ssize_t size; /* size */ + size_t size; /* size */ }; struct fastrpc_ioctl_mmap { int fd; /* ion fd */ uint32_t flags; /* flags for dsp to map with */ - uintptr_t __user *vaddrin; /* optional virtual address */ - ssize_t size; /* size */ + uintptr_t vaddrin; /* optional virtual address */ + size_t size; /* size */ uintptr_t vaddrout; /* dsps virtual address */ }; struct smq_null_invoke { - struct smq_invoke_ctx *ctx; /* invoke caller context */ + uint64_t ctx; /* invoke caller context */ uint32_t handle; /* handle to invoke */ uint32_t sc; /* scalars structure describing the data */ }; struct smq_phy_page { unsigned long addr; /* physical address */ - ssize_t size; /* size of contiguous region */ + size_t size; /* size of contiguous region */ }; struct smq_invoke_buf { @@ -164,21 +164,22 @@ struct smq_msg { }; struct smq_invoke_rsp { - struct smq_invoke_ctx *ctx; /* invoke caller context */ + uint64_t ctx; /* invoke caller context */ int retval; /* invoke return value */ }; static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg_t *pra, uint32_t sc) { - int len = REMOTE_SCALARS_LENGTH(sc); + unsigned int len = REMOTE_SCALARS_LENGTH(sc); + return (struct smq_invoke_buf *)(&pra[len]); } static inline struct smq_phy_page *smq_phy_page_start(uint32_t sc, struct smq_invoke_buf *buf) { - int nTotal = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc); + uint32_t nTotal = REMOTE_SCALARS_INBUFS(sc)+REMOTE_SCALARS_OUTBUFS(sc); return (struct smq_phy_page *)(&buf[nTotal]); } diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index a46f4eef3537620066fb709ee4f6d26677d235c8..b5fa46591dc2f1a5e840715f7fadf142fc6a83aa 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2018 The Linux Foundation. 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 and @@ -804,12 +804,12 @@ static void dci_process_ctrl_status(unsigned char *buf, int len, int token) { struct diag_ctrl_dci_status *header = NULL; unsigned char *temp = buf; - uint32_t read_len = 0; + unsigned int read_len = 0; uint8_t i; int peripheral_mask, status; - if (!buf || (len < sizeof(struct diag_ctrl_dci_status))) { - pr_err("diag: In %s, invalid buf %pK or length: %d\n", + if (!buf || len < 2 || (len < sizeof(struct diag_ctrl_dci_status))) { + pr_err("diag: In %s, invalid buf %p or length: %d\n", __func__, buf, len); return; } @@ -824,7 +824,7 @@ static void dci_process_ctrl_status(unsigned char *buf, int len, int token) read_len += sizeof(struct diag_ctrl_dci_status); for (i = 0; i < header->count; i++) { - if (read_len > len) { + if (read_len > (len - 2)) { pr_err("diag: In %s, Invalid length len: %d\n", __func__, len); return; @@ -866,7 +866,9 @@ static void dci_process_ctrl_handshake_pkt(unsigned char *buf, int len, unsigned char *temp = buf; int err = 0; - if (!buf || (len < sizeof(struct diag_ctrl_dci_handshake_pkt))) + if (!buf) + return; + if (len < 0 || len < sizeof(struct diag_ctrl_dci_handshake_pkt)) return; if (!VALID_DCI_TOKEN(token)) @@ -1106,18 +1108,32 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; - length = *(uint16_t *)(buf + 1); /* total length of event series */ - if (length == 0) { - pr_err("diag: Incoming dci event length is invalid\n"); + if (!buf) { + pr_err("diag: In %s buffer is NULL\n", __func__); return; } - /* Move directly to the start of the event series. 1 byte for - * event code and 2 bytes for the length field. - */ - /* The length field indicates the total length removing the cmd_code - * and the lenght field. The event parsing in that case should happen + + /* + * 1 byte for event code and 2 bytes for the length field. + * The length field indicates the total length removing the cmd_code + * and the length field. The event parsing in that case should happen * till the end. */ + if (len < 3) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); + return; + } + length = *(uint16_t *)(buf + 1); /* total length of event series */ + if ((length == 0) || (len != (length + 3))) { + pr_err("diag: Incoming dci event length: %d is invalid\n", + length); + return; + } + /* + * Move directly to the start of the event series. + * The event parsing should happen from start of event + * series till the end. + */ temp_len = 3; while (temp_len < length) { event_id_packet = *(uint16_t *)(buf + temp_len); @@ -1134,30 +1150,60 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) * necessary. */ timestamp_len = 8; - memcpy(timestamp, buf + temp_len + 2, timestamp_len); + if ((temp_len + timestamp_len + 2) <= len) + memcpy(timestamp, buf + temp_len + 2, + timestamp_len); + else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } } /* 13th and 14th bit represent the payload length */ if (((event_id_packet & 0x6000) >> 13) == 3) { payload_len_field = 1; - payload_len = *(uint8_t *) + if ((temp_len + timestamp_len + 3) <= len) { + payload_len = *(uint8_t *) (buf + temp_len + 2 + timestamp_len); - if (payload_len < (MAX_EVENT_SIZE - 13)) { - /* copy the payload length and the payload */ + } else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } + if ((payload_len < (MAX_EVENT_SIZE - 13)) && + ((temp_len + timestamp_len + payload_len + 3) <= len)) { + /* + * Copy the payload length and the payload + * after skipping temp_len bytes for already + * parsed packet, timestamp_len for timestamp + * buffer, 2 bytes for event_id_packet. + */ memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, 1); memcpy(event_data + 13, buf + temp_len + 2 + timestamp_len + 1, payload_len); } else { - pr_err("diag: event > %d, payload_len = %d\n", - (MAX_EVENT_SIZE - 13), payload_len); + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 13), payload_len, temp_len); return; } } else { payload_len_field = 0; payload_len = (event_id_packet & 0x6000) >> 13; - /* copy the payload */ - memcpy(event_data + 12, buf + temp_len + 2 + + /* + * Copy the payload after skipping temp_len bytes + * for already parsed packet, timestamp_len for + * timestamp buffer, 2 bytes for event_id_packet. + */ + if ((payload_len < (MAX_EVENT_SIZE - 12)) && + ((temp_len + timestamp_len + payload_len + 2) <= len)) + memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, payload_len); + else { + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 12), payload_len, temp_len); + return; + } } /* Before copying the data to userspace, check if we are still @@ -1275,19 +1321,19 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token) pr_err("diag: In %s buffer is NULL\n", __func__); return; } - - /* The first six bytes for the incoming log packet contains - * Command code (2), the length of the packet (2) and the length - * of the log (2) + /* + * The first eight bytes for the incoming log packet contains + * Command code (2), the length of the packet (2), the length + * of the log (2) and log code (2) */ - log_code = *(uint16_t *)(buf + 6); - read_bytes += sizeof(uint16_t) + 6; - if (read_bytes > len) { - pr_err("diag: Invalid length in %s, len: %d, read: %d", - __func__, len, read_bytes); + if (len < 8) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); return; } + log_code = *(uint16_t *)(buf + 6); + read_bytes += sizeof(uint16_t) + 6; + /* parse through log mask table of each client and check mask */ mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { @@ -1325,6 +1371,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) * which log entries in the cumulative logs that need * to be updated on the peripheral. */ + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); if (entry->client_info.token != DCI_LOCAL_PROC) @@ -1336,6 +1383,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) client_log_mask_ptr += 514; } } + mutex_unlock(&driver->dci_mutex); mutex_lock(&dci_log_mask_mutex); /* Update the appropriate dirty bits in the cumulative mask */ @@ -3009,13 +3057,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) return DIAG_DCI_NOT_SUPPORTED; token = entry->client_info.token; - - mutex_lock(&driver->dci_mutex); /* * Remove the entry from the list before freeing the buffers * to ensure that we don't have any invalid access. */ - list_del(&entry->track); + if (!list_empty(&entry->track)) + list_del(&entry->track); driver->num_dci_client--; /* * Clear the client's log and event masks, update the cumulative @@ -3044,7 +3091,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) req_entry = list_entry(start, struct dci_pkt_req_entry_t, track); if (req_entry->client_id == entry->client_info.client_id) { - list_del(&req_entry->track); + if (!list_empty(&req_entry->track)) + list_del(&req_entry->track); kfree(req_entry); } } @@ -3053,7 +3101,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) mutex_lock(&entry->write_buf_mutex); list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf, buf_track) { - list_del(&buf_entry->buf_track); + if (!list_empty(&buf_entry->buf_track)) + list_del(&buf_entry->buf_track); if (buf_entry->buf_type == DCI_BUF_SECONDARY) { mutex_lock(&buf_entry->data_mutex); diagmem_free(driver, buf_entry->data, POOL_TYPE_DCI); @@ -3122,8 +3171,6 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); - mutex_unlock(&driver->dci_mutex); - return DIAG_DCI_NO_ERROR; } diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index ab9d5fb4d95544fd11933ce7efdfdca44b6032d9..4e3c2860687511f77562d834c5d511923f182fa4 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2015, 2017-2018 The Linux Foundation. + * 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 and @@ -322,9 +323,9 @@ static int diagchar_open(struct inode *inode, struct file *file) return -ENOMEM; fail: - mutex_unlock(&driver->diagchar_mutex); driver->num_clients--; - pr_alert("diag: Insufficient memory for new client"); + mutex_unlock(&driver->diagchar_mutex); + pr_err_ratelimited("diag: Insufficient memory for new client"); return -ENOMEM; } @@ -348,9 +349,11 @@ static int diagchar_close(struct inode *inode, struct file *file) * This will specially help in case of ungraceful exit of any DCI client * This call will remove any pending registrations of such client */ - dci_entry = dci_lookup_client_entry_pid(current->tgid); + mutex_lock(&driver->dci_mutex); + dci_entry = dci_lookup_client_entry_pid(current->pid); if (dci_entry) diag_dci_deinit_client(dci_entry); + mutex_unlock(&driver->dci_mutex); /* If the exiting process is the socket process */ mutex_lock(&driver->diagchar_mutex); if (driver->socket_process && @@ -1049,14 +1052,18 @@ static int diag_ioctl_lsm_deinit(void) { int i; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; - if (i == driver->num_clients) + if (i == driver->num_clients) { + mutex_unlock(&driver->diagchar_mutex); return -EINVAL; + } driver->data_ready[i] |= DEINIT_TYPE; + mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); return 1; @@ -1257,22 +1264,32 @@ long diagchar_compat_ioctl(struct file *filp, result = diag_ioctl_dci_reg(ioarg); break; case DIAG_IOCTL_DCI_DEINIT: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } dci_client = diag_dci_get_client_entry(client_id); - if (!dci_client) + if (!dci_client) { + mutex_unlock(&driver->dci_mutex); return DIAG_DCI_NOT_SUPPORTED; + } result = diag_dci_deinit_client(dci_client); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_SUPPORT: result = diag_ioctl_dci_support(ioarg); break; case DIAG_IOCTL_DCI_HEALTH_STATS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_health_stats(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_LOG_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_log_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: mutex_lock(&driver->dci_mutex); @@ -1280,16 +1297,24 @@ long diagchar_compat_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_log_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_EVENTS: + mutex_lock(&driver->dci_mutex); if (copy_from_user(&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_event_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_LSM_DEINIT: result = diag_ioctl_lsm_deinit(); @@ -1309,7 +1334,9 @@ long diagchar_compat_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_vote_real_time(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_GET_REAL_TIME: result = diag_ioctl_get_real_time(ioarg); @@ -1356,22 +1383,32 @@ long diagchar_ioctl(struct file *filp, result = diag_ioctl_dci_reg(ioarg); break; case DIAG_IOCTL_DCI_DEINIT: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } dci_client = diag_dci_get_client_entry(client_id); - if (!dci_client) + if (!dci_client) { + mutex_unlock(&driver->dci_mutex); return DIAG_DCI_NOT_SUPPORTED; + } result = diag_dci_deinit_client(dci_client); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_SUPPORT: result = diag_ioctl_dci_support(ioarg); break; case DIAG_IOCTL_DCI_HEALTH_STATS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_health_stats(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_LOG_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_log_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: mutex_lock(&driver->dci_mutex); @@ -1379,16 +1416,24 @@ long diagchar_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: + mutex_lock(&driver->dci_mutex); if (copy_from_user((void *)&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_log_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_EVENTS: + mutex_lock(&driver->dci_mutex); if (copy_from_user(&client_id, (void __user *)ioarg, - sizeof(int))) + sizeof(int))) { + mutex_unlock(&driver->dci_mutex); return -EFAULT; + } result = diag_dci_clear_event_mask(client_id); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_LSM_DEINIT: result = diag_ioctl_lsm_deinit(); @@ -1408,7 +1453,9 @@ long diagchar_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_vote_real_time(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_GET_REAL_TIME: result = diag_ioctl_get_real_time(ioarg); @@ -1585,6 +1632,7 @@ exit: goto end; } } + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) { if (driver->smd_dci[i].ch) { queue_work(driver->diag_dci_wq, @@ -1602,6 +1650,7 @@ exit: } } } + mutex_unlock(&driver->diagchar_mutex); mutex_unlock(&driver->dci_mutex); goto end; } diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c index 9d4b9b2f741708f2459f2264ae6b7c98de5fa3a8..a15acd12084a8990fdc7927d854a070257adbf01 100644 --- a/drivers/coresight/coresight-tmc.c +++ b/drivers/coresight/coresight-tmc.c @@ -1576,7 +1576,7 @@ out: dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", __func__, len, (int) (drvdata->size - *ppos)); - mutex_lock(&drvdata->usb_lock); + mutex_unlock(&drvdata->usb_lock); return len; } diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index e6be63561fa699a28053c7528056dcd08ffb2285..521bf7761ae7cfb8576bca76169bf2fd0a9c5802 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -36,14 +36,29 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; + unsigned int sampling_rate; unsigned int max_load = 0; unsigned int ignore_nice; unsigned int j; - if (dbs_data->cdata->governor == GOV_ONDEMAND) + if (dbs_data->cdata->governor == GOV_ONDEMAND) { + struct od_cpu_dbs_info_s *od_dbs_info = + dbs_data->cdata->get_cpu_dbs_info_s(cpu); + + /* + * Sometimes, the ondemand governor uses an additional + * multiplier to give long delays. So apply this multiplier to + * the 'sampling_rate', so as to keep the wake-up-from-idle + * detection logic a bit conservative. + */ + sampling_rate = od_tuners->sampling_rate; + sampling_rate *= od_dbs_info->rate_mult; + ignore_nice = od_tuners->ignore_nice_load; - else + } else { + sampling_rate = cs_tuners->sampling_rate; ignore_nice = cs_tuners->ignore_nice_load; + } policy = cdbs->cur_policy; @@ -96,7 +111,46 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) if (unlikely(!wall_time || wall_time < idle_time)) continue; - load = 100 * (wall_time - idle_time) / wall_time; + /* + * If the CPU had gone completely idle, and a task just woke up + * on this CPU now, it would be unfair to calculate 'load' the + * usual way for this elapsed time-window, because it will show + * near-zero load, irrespective of how CPU intensive that task + * actually is. This is undesirable for latency-sensitive bursty + * workloads. + * + * To avoid this, we reuse the 'load' from the previous + * time-window and give this task a chance to start with a + * reasonably high CPU frequency. (However, we shouldn't over-do + * this copy, lest we get stuck at a high load (high frequency) + * for too long, even when the current system load has actually + * dropped down. So we perform the copy only once, upon the + * first wake-up from idle.) + * + * Detecting this situation is easy: the governor's deferrable + * timer would not have fired during CPU-idle periods. Hence + * an unusually large 'wall_time' (as compared to the sampling + * rate) indicates this scenario. + * + * prev_load can be zero in two cases and we must recalculate it + * for both cases: + * - during long idle intervals + * - explicitly set to zero + */ + if (unlikely(wall_time > (2 * sampling_rate) && + j_cdbs->prev_load)) { + load = j_cdbs->prev_load; + + /* + * Perform a destructive copy, to ensure that we copy + * the previous load only once, upon the first wake-up + * from idle. + */ + j_cdbs->prev_load = 0; + } else { + load = 100 * (wall_time - idle_time) / wall_time; + j_cdbs->prev_load = load; + } if (load > max_load) max_load = load; @@ -314,11 +368,18 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs = dbs_data->cdata->get_cpu_cdbs(j); + unsigned int prev_load; j_cdbs->cpu = j; j_cdbs->cur_policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); + + prev_load = (unsigned int) + (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); + j_cdbs->prev_load = 100 * prev_load / + (unsigned int) j_cdbs->prev_cpu_wall; + if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; @@ -362,6 +423,11 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, break; case CPUFREQ_GOV_LIMITS: + mutex_lock(&dbs_data->mutex); + if (!cpu_cdbs->cur_policy) { + mutex_unlock(&dbs_data->mutex); + break; + } mutex_lock(&cpu_cdbs->timer_mutex); if (policy->max < cpu_cdbs->cur_policy->cur) __cpufreq_driver_target(cpu_cdbs->cur_policy, @@ -371,6 +437,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cpu_cdbs->timer_mutex); + mutex_unlock(&dbs_data->mutex); break; } return 0; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index b5f2b8618949dc75d55202d7b76e56e1e0c52a5f..279318f6753440b2ff9af7330e136fefdb2f3772 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -134,6 +134,13 @@ struct cpu_dbs_common_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; + /* + * Used to keep track of load in the previous interval. However, when + * explicitly set to zero, it is used as a flag to ensure that we copy + * the previous load to the current interval only once, upon the first + * wake-up from idle. + */ + unsigned int prev_load; struct cpufreq_policy *cur_policy; struct delayed_work work; /* diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 5926916fce5fe3ecad88562fd94f0101e2e5b433..b6979cd744cf29e979cd4bf09bc1086e80bbacce 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -574,14 +574,12 @@ failed: void free_cluster_node(struct lpm_cluster *cluster) { - struct list_head *list; int i; + struct lpm_cluster *cl, *m; - list_for_each(list, &cluster->child) { - struct lpm_cluster *n; - n = list_entry(list, typeof(*n), list); - list_del(list); - free_cluster_node(n); + list_for_each_entry_safe(cl, m, &cluster->child, list) { + list_del(&cl->list); + free_cluster_node(cl); }; if (cluster->cpu) { diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 6b1ae7f50804a68b8cff2635624981cccb3a7297..5e31f97c5bb981e4ecdbdfb5604581bc32bff9fc 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -307,6 +307,14 @@ static int hiddev_open(struct inode *inode, struct file *file) spin_unlock_irq(&list->hiddev->list_lock); mutex_lock(&hiddev->existancelock); + /* + * recheck exist with existance lock held to + * avoid opening a disconnected device + */ + if (!list->hiddev->exist) { + res = -ENODEV; + goto bail_unlock; + } if (!list->hiddev->open++) if (list->hiddev->exist) { struct hid_device *hid = hiddev->hid; @@ -321,6 +329,10 @@ static int hiddev_open(struct inode *inode, struct file *file) return 0; bail_unlock: mutex_unlock(&hiddev->existancelock); + + spin_lock_irq(&list->hiddev->list_lock); + list_del(&list->node); + spin_unlock_irq(&list->hiddev->list_lock); bail: file->private_data = NULL; vfree(list); diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index a9f8f925ba2b22c32c146226745d3e2acca894b1..5a7be4c559f3bccdaa755f3f30c8e7f4dbc35ba3 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -232,13 +232,17 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, /* Walk this report and pull out the info we need */ while (i < length) { - prefix = report[i]; - - /* Skip over prefix */ - i++; + prefix = report[i++]; /* Determine data size and save the data in the proper variable */ - size = PREF_SIZE(prefix); + size = (1U << PREF_SIZE(prefix)) >> 1; + if (i + size > length) { + dev_err(ddev, + "Not enough data (need %d, have %d)\n", + i + size, length); + break; + } + switch (size) { case 1: data = report[i]; @@ -246,8 +250,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, case 2: data16 = get_unaligned_le16(&report[i]); break; - case 3: - size = 4; + case 4: data32 = get_unaligned_le32(&report[i]); break; } diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index b4616f60dce12c2b938a33711a78082828d9b18f..7dd00e1c88255748bbf8a28c759e39d1acf7e60f 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 The Linux Foundation. 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 and @@ -384,7 +384,7 @@ static int msm_fd_open(struct file *file) ctx->mem_pool.fd_device = ctx->fd_device; ctx->mem_pool.domain_num = ctx->fd_device->iommu_domain_num; - ctx->stats = vmalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); + ctx->stats = vzalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); if (!ctx->stats) { dev_err(device->dev, "No memory for face statistics\n"); ret = -ENOMEM; diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index a07e4f61ab14ccd9491f8b3bf7d59772b2ff93d1..75dd0474317d32365ef0df3c4a99485f9fd0b620 100755 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2018 The Linux Foundation. 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 and @@ -52,6 +52,11 @@ static int32_t msm_actuator_piezo_set_default_focus( struct msm_camera_i2c_reg_setting reg_setting; CDBG("Enter\n"); + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } + if (a_ctrl->curr_step_pos != 0) { a_ctrl->i2c_tbl_index = 0; a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, @@ -533,6 +538,11 @@ static int32_t msm_actuator_piezo_move_focus( return -EFAULT; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } + if (dest_step_position > a_ctrl->total_steps) { pr_err("Step pos greater than total steps = %d\n", dest_step_position); @@ -603,6 +613,10 @@ static int32_t msm_actuator_move_focus( pr_err("Invalid direction = %d\n", dir); return -EFAULT; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } if (dest_step_pos > a_ctrl->total_steps) { pr_err("Step pos greater than total steps = %d\n", dest_step_pos); @@ -614,6 +628,8 @@ static int32_t msm_actuator_move_focus( a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); while (a_ctrl->curr_step_pos != dest_step_pos) { + if (a_ctrl->curr_region_index >= a_ctrl->region_size) + break; step_boundary = a_ctrl->region_params[a_ctrl->curr_region_index]. step_bound[dir]; @@ -699,6 +715,10 @@ static int32_t msm_actuator_bivcm_move_focus( pr_err("Invalid direction = %d\n", dir); return -EFAULT; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return -EFAULT; + } if (dest_step_pos > a_ctrl->total_steps) { pr_err("Step pos greater than total steps = %d\n", dest_step_pos); @@ -710,6 +730,8 @@ static int32_t msm_actuator_bivcm_move_focus( a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); while (a_ctrl->curr_step_pos != dest_step_pos) { + if (a_ctrl->curr_region_index >= a_ctrl->region_size) + break; step_boundary = a_ctrl->region_params[a_ctrl->curr_region_index]. step_bound[dir]; @@ -1097,6 +1119,18 @@ static int32_t msm_actuator_set_position( return -EFAULT; } + if (!a_ctrl || !a_ctrl->func_tbl || + !a_ctrl->func_tbl->actuator_parse_i2c_params || + !a_ctrl->i2c_reg_tbl) { + pr_err("failed. NULL actuator pointers."); + return -EFAULT; + } + + if (a_ctrl->actuator_state != ACT_OPS_ACTIVE) { + pr_err("failed. Invalid actuator state."); + return -EFAULT; + } + a_ctrl->i2c_tbl_index = 0; for (index = 0; index < set_pos->number_of_steps; index++) { next_lens_position = set_pos->pos[index]; @@ -1185,12 +1219,10 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, a_ctrl->region_size = set_info->af_tuning_params.region_size; a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step; - a_ctrl->total_steps = set_info->af_tuning_params.total_steps; if (copy_from_user(&a_ctrl->region_params, (void *)set_info->af_tuning_params.region_params, a_ctrl->region_size * sizeof(struct region_params_t))) { - a_ctrl->total_steps = 0; pr_err("Error copying region_params\n"); return -EFAULT; } @@ -1221,6 +1253,7 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, (a_ctrl->i2c_reg_tbl != NULL)) { kfree(a_ctrl->i2c_reg_tbl); } + a_ctrl->i2c_reg_tbl = NULL; a_ctrl->i2c_reg_tbl = kzalloc(sizeof(struct msm_camera_i2c_reg_array) * @@ -1230,6 +1263,8 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, return -ENOMEM; } + a_ctrl->total_steps = set_info->af_tuning_params.total_steps; + if (copy_from_user(&a_ctrl->reg_tbl, (void *)set_info->actuator_params.reg_tbl_params, a_ctrl->reg_tbl_size * diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7156cc138f184c1757899ffccee410942cb4d9df..e25241f92c418577013e26565a98afad5e91de85 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o obj-$(CONFIG_ICS932S401) += ics932s401.o -obj-$(CONFIG_LKDTM) += lkdtm.o +obj-$(CONFIG_LKDTM) += lkdtm/ obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3370a4138e942621a008573b1fa1ad6912b1c75c --- /dev/null +++ b/drivers/misc/lkdtm/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_LKDTM) += lkdtm.o + +lkdtm-$(CONFIG_LKDTM) += core.o +lkdtm-$(CONFIG_LKDTM) += bugs.o +lkdtm-$(CONFIG_LKDTM) += heap.o +lkdtm-$(CONFIG_LKDTM) += perms.o +lkdtm-$(CONFIG_LKDTM) += refcount.o +lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o +lkdtm-$(CONFIG_LKDTM) += usercopy.o + +KCOV_INSTRUMENT_rodata.o := n + +OBJCOPYFLAGS := +OBJCOPYFLAGS_rodata_objcopy.o := \ + --set-section-flags .text=alloc,readonly \ + --rename-section .text=.rodata +targets += rodata.o rodata_objcopy.o +$(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE + $(call if_changed,objcopy) diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c new file mode 100644 index 0000000000000000000000000000000000000000..7eebbdfbcacd0a51aef6f1d0c70e794b45ac3c03 --- /dev/null +++ b/drivers/misc/lkdtm/bugs.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests related to logic bugs (e.g. bad dereferences, + * bad alignment, bad loops, bad locking, bad scheduling, deep stacks, and + * lockups) along with other things that don't fit well into existing LKDTM + * test source files. + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include + +struct lkdtm_list { + struct list_head node; +}; + +/* + * Make sure our attempts to over run the kernel stack doesn't trigger + * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we + * recurse past the end of THREAD_SIZE by default. + */ +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) +#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) +#else +#define REC_STACK_SIZE (THREAD_SIZE / 8) +#endif +#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) + +static int recur_count = REC_NUM_DEFAULT; + +static DEFINE_SPINLOCK(lock_me_up); + +static int recursive_loop(int remaining) +{ + char buf[REC_STACK_SIZE]; + + /* Make sure compiler does not optimize this away. */ + memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); + if (!remaining) + return 0; + else + return recursive_loop(remaining - 1); +} + +/* If the depth is negative, use the default, otherwise keep parameter. */ +void __init lkdtm_bugs_init(int *recur_param) +{ + if (*recur_param < 0) + *recur_param = recur_count; + else + recur_count = *recur_param; +} + +void lkdtm_PANIC(void) +{ + panic("dumptest"); +} + +void lkdtm_BUG(void) +{ + BUG(); +} + +static int warn_counter; + +void lkdtm_WARNING(void) +{ + WARN(1, "Warning message trigger count: %d\n", warn_counter++); +} + +void lkdtm_EXCEPTION(void) +{ + *((volatile int *) 0) = 0; +} + +void lkdtm_LOOP(void) +{ + for (;;) + ; +} + +void lkdtm_OVERFLOW(void) +{ + (void) recursive_loop(recur_count); +} + +static noinline void __lkdtm_CORRUPT_STACK(void *stack) +{ + memset(stack, '\xff', 64); +} + +/* This should trip the stack canary, not corrupt the return address. */ +noinline void lkdtm_CORRUPT_STACK(void) +{ + /* Use default char array length that triggers stack protection. */ + char data[8] __aligned(sizeof(void *)); + + __lkdtm_CORRUPT_STACK(&data); + + pr_info("Corrupted stack containing char array ...\n"); +} + +/* Same as above but will only get a canary with -fstack-protector-strong */ +noinline void lkdtm_CORRUPT_STACK_STRONG(void) +{ + union { + unsigned short shorts[4]; + unsigned long *ptr; + } data __aligned(sizeof(void *)); + + __lkdtm_CORRUPT_STACK(&data); + + pr_info("Corrupted stack containing union ...\n"); +} + +void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) +{ + static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5}; + u32 *p; + u32 val = 0x12345678; + + p = (u32 *)(data + 1); + if (*p == 0) + val = 0x87654321; + *p = val; +} + +void lkdtm_SOFTLOCKUP(void) +{ + preempt_disable(); + for (;;) + cpu_relax(); +} + +void lkdtm_HARDLOCKUP(void) +{ + local_irq_disable(); + for (;;) + cpu_relax(); +} + +void lkdtm_SPINLOCKUP(void) +{ + /* Must be called twice to trigger. */ + spin_lock(&lock_me_up); + /* Let sparse know we intended to exit holding the lock. */ + __release(&lock_me_up); +} + +void lkdtm_HUNG_TASK(void) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); +} + +void lkdtm_CORRUPT_LIST_ADD(void) +{ + /* + * Initially, an empty list via LIST_HEAD: + * test_head.next = &test_head + * test_head.prev = &test_head + */ + LIST_HEAD(test_head); + struct lkdtm_list good, bad; + void *target[2] = { }; + void *redirection = ⌖ + + pr_info("attempting good list addition\n"); + + /* + * Adding to the list performs these actions: + * test_head.next->prev = &good.node + * good.node.next = test_head.next + * good.node.prev = test_head + * test_head.next = good.node + */ + list_add(&good.node, &test_head); + + pr_info("attempting corrupted list addition\n"); + /* + * In simulating this "write what where" primitive, the "what" is + * the address of &bad.node, and the "where" is the address held + * by "redirection". + */ + test_head.next = redirection; + list_add(&bad.node, &test_head); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_add() corruption not detected!\n"); +} + +void lkdtm_CORRUPT_LIST_DEL(void) +{ + LIST_HEAD(test_head); + struct lkdtm_list item; + void *target[2] = { }; + void *redirection = ⌖ + + list_add(&item.node, &test_head); + + pr_info("attempting good list removal\n"); + list_del(&item.node); + + pr_info("attempting corrupted list removal\n"); + list_add(&item.node, &test_head); + + /* As with the list_add() test above, this corrupts "next". */ + item.node.next = redirection; + list_del(&item.node); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_del() corruption not detected!\n"); +} + +/* Test if unbalanced set_fs(KERNEL_DS)/set_fs(USER_DS) check exists. */ +void lkdtm_CORRUPT_USER_DS(void) +{ + pr_info("setting bad task size limit\n"); + set_fs(KERNEL_DS); + + /* Make sure we do not keep running with a KERNEL_DS! */ + force_sig(SIGKILL, current); +} + +/* Test that VMAP_STACK is actually allocating with a leading guard page */ +void lkdtm_STACK_GUARD_PAGE_LEADING(void) +{ + const unsigned char *stack = task_stack_page(current); + const unsigned char *ptr = stack - 1; + volatile unsigned char byte; + + pr_info("attempting bad read from page below current stack\n"); + + byte = *ptr; + + pr_err("FAIL: accessed page before stack!\n"); +} + +/* Test that VMAP_STACK is actually allocating with a trailing guard page */ +void lkdtm_STACK_GUARD_PAGE_TRAILING(void) +{ + const unsigned char *stack = task_stack_page(current); + const unsigned char *ptr = stack + THREAD_SIZE; + volatile unsigned char byte; + + pr_info("attempting bad read from page above current stack\n"); + + byte = *ptr; + + pr_err("FAIL: accessed page after stack!\n"); +} diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c new file mode 100644 index 0000000000000000000000000000000000000000..2154d1bfd18b610b60f0fc8409cf7bf8919f2aad --- /dev/null +++ b/drivers/misc/lkdtm/core.c @@ -0,0 +1,505 @@ +/* + * Linux Kernel Dump Test Module for testing kernel crashes conditions: + * induces system failures at predefined crashpoints and under predefined + * operational conditions in order to evaluate the reliability of kernel + * sanity checking and crash dumps obtained using different dumping + * solutions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Author: Ankita Garg + * + * It is adapted from the Linux Kernel Dump Test Tool by + * Fernando Luis Vazquez Cao + * + * Debugfs support added by Simon Kagstrom + * + * See Documentation/fault-injection/provoke-crashes.txt for instructions + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_IDE +#include +#endif + +#define DEFAULT_COUNT 10 + +static int lkdtm_debugfs_open(struct inode *inode, struct file *file); +static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, + size_t count, loff_t *off); +static ssize_t direct_entry(struct file *f, const char __user *user_buf, + size_t count, loff_t *off); + +#ifdef CONFIG_KPROBES +static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs); +static ssize_t lkdtm_debugfs_entry(struct file *f, + const char __user *user_buf, + size_t count, loff_t *off); +# define CRASHPOINT_KPROBE(_symbol) \ + .kprobe = { \ + .symbol_name = (_symbol), \ + .pre_handler = lkdtm_kprobe_handler, \ + }, +# define CRASHPOINT_WRITE(_symbol) \ + (_symbol) ? lkdtm_debugfs_entry : direct_entry +#else +# define CRASHPOINT_KPROBE(_symbol) +# define CRASHPOINT_WRITE(_symbol) direct_entry +#endif + +/* Crash points */ +struct crashpoint { + const char *name; + const struct file_operations fops; + struct kprobe kprobe; +}; + +#define CRASHPOINT(_name, _symbol) \ + { \ + .name = _name, \ + .fops = { \ + .read = lkdtm_debugfs_read, \ + .llseek = generic_file_llseek, \ + .open = lkdtm_debugfs_open, \ + .write = CRASHPOINT_WRITE(_symbol) \ + }, \ + CRASHPOINT_KPROBE(_symbol) \ + } + +/* Define the possible places where we can trigger a crash point. */ +static struct crashpoint crashpoints[] = { + CRASHPOINT("DIRECT", NULL), +#ifdef CONFIG_KPROBES + CRASHPOINT("INT_HARDWARE_ENTRY", "do_IRQ"), + CRASHPOINT("INT_HW_IRQ_EN", "handle_irq_event"), + CRASHPOINT("INT_TASKLET_ENTRY", "tasklet_action"), + CRASHPOINT("FS_DEVRW", "ll_rw_block"), + CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), + CRASHPOINT("TIMERADD", "hrtimer_start"), + CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"), +# ifdef CONFIG_IDE + CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), +# endif +#endif +}; + + +/* Crash types. */ +struct crashtype { + const char *name; + void (*func)(void); +}; + +#define CRASHTYPE(_name) \ + { \ + .name = __stringify(_name), \ + .func = lkdtm_ ## _name, \ + } + +/* Define the possible types of crashes that can be triggered. */ +static const struct crashtype crashtypes[] = { + CRASHTYPE(PANIC), + CRASHTYPE(BUG), + CRASHTYPE(WARNING), + CRASHTYPE(EXCEPTION), + CRASHTYPE(LOOP), + CRASHTYPE(OVERFLOW), + CRASHTYPE(CORRUPT_LIST_ADD), + CRASHTYPE(CORRUPT_LIST_DEL), + CRASHTYPE(CORRUPT_USER_DS), + CRASHTYPE(CORRUPT_STACK), + CRASHTYPE(CORRUPT_STACK_STRONG), + CRASHTYPE(STACK_GUARD_PAGE_LEADING), + CRASHTYPE(STACK_GUARD_PAGE_TRAILING), + CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), + CRASHTYPE(OVERWRITE_ALLOCATION), + CRASHTYPE(WRITE_AFTER_FREE), + CRASHTYPE(READ_AFTER_FREE), + CRASHTYPE(WRITE_BUDDY_AFTER_FREE), + CRASHTYPE(READ_BUDDY_AFTER_FREE), + CRASHTYPE(SOFTLOCKUP), + CRASHTYPE(HARDLOCKUP), + CRASHTYPE(SPINLOCKUP), + CRASHTYPE(HUNG_TASK), + CRASHTYPE(EXEC_DATA), + CRASHTYPE(EXEC_STACK), + CRASHTYPE(EXEC_KMALLOC), + CRASHTYPE(EXEC_VMALLOC), + CRASHTYPE(EXEC_RODATA), + CRASHTYPE(EXEC_USERSPACE), + CRASHTYPE(ACCESS_USERSPACE), + CRASHTYPE(WRITE_RO), + CRASHTYPE(WRITE_RO_AFTER_INIT), + CRASHTYPE(WRITE_KERN), + CRASHTYPE(REFCOUNT_INC_OVERFLOW), + CRASHTYPE(REFCOUNT_ADD_OVERFLOW), + CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW), + CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW), + CRASHTYPE(REFCOUNT_DEC_ZERO), + CRASHTYPE(REFCOUNT_DEC_NEGATIVE), + CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE), + CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE), + CRASHTYPE(REFCOUNT_INC_ZERO), + CRASHTYPE(REFCOUNT_ADD_ZERO), + CRASHTYPE(REFCOUNT_INC_SATURATED), + CRASHTYPE(REFCOUNT_DEC_SATURATED), + CRASHTYPE(REFCOUNT_ADD_SATURATED), + CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED), + CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED), + CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED), + CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED), + CRASHTYPE(REFCOUNT_TIMING), + CRASHTYPE(ATOMIC_TIMING), + CRASHTYPE(USERCOPY_HEAP_SIZE_TO), + CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), + CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO), + CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM), + CRASHTYPE(USERCOPY_STACK_FRAME_TO), + CRASHTYPE(USERCOPY_STACK_FRAME_FROM), + CRASHTYPE(USERCOPY_STACK_BEYOND), + CRASHTYPE(USERCOPY_KERNEL), +}; + + +/* Global kprobe entry and crashtype. */ +static struct kprobe *lkdtm_kprobe; +static struct crashpoint *lkdtm_crashpoint; +static const struct crashtype *lkdtm_crashtype; + +/* Module parameters */ +static int recur_count = -1; +module_param(recur_count, int, 0644); +MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); + +static char* cpoint_name; +module_param(cpoint_name, charp, 0444); +MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); + +static char* cpoint_type; +module_param(cpoint_type, charp, 0444); +MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ + "hitting the crash point"); + +static int cpoint_count = DEFAULT_COUNT; +module_param(cpoint_count, int, 0644); +MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ + "crash point is to be hit to trigger action"); + + +/* Return the crashtype number or NULL if the name is invalid */ +static const struct crashtype *find_crashtype(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { + if (!strcmp(name, crashtypes[i].name)) + return &crashtypes[i]; + } + + return NULL; +} + +/* + * This is forced noinline just so it distinctly shows up in the stackdump + * which makes validation of expected lkdtm crashes easier. + */ +static noinline void lkdtm_do_action(const struct crashtype *crashtype) +{ + if (WARN_ON(!crashtype || !crashtype->func)) + return; + crashtype->func(); +} + +static int lkdtm_register_cpoint(struct crashpoint *crashpoint, + const struct crashtype *crashtype) +{ + int ret; + + /* If this doesn't have a symbol, just call immediately. */ + if (!crashpoint->kprobe.symbol_name) { + lkdtm_do_action(crashtype); + return 0; + } + + if (lkdtm_kprobe != NULL) + unregister_kprobe(lkdtm_kprobe); + + lkdtm_crashpoint = crashpoint; + lkdtm_crashtype = crashtype; + lkdtm_kprobe = &crashpoint->kprobe; + ret = register_kprobe(lkdtm_kprobe); + if (ret < 0) { + pr_info("Couldn't register kprobe %s\n", + crashpoint->kprobe.symbol_name); + lkdtm_kprobe = NULL; + lkdtm_crashpoint = NULL; + lkdtm_crashtype = NULL; + } + + return ret; +} + +#ifdef CONFIG_KPROBES +/* Global crash counter and spinlock. */ +static int crash_count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(crash_count_lock); + +/* Called by kprobe entry points. */ +static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs) +{ + unsigned long flags; + bool do_it = false; + + if (WARN_ON(!lkdtm_crashpoint || !lkdtm_crashtype)) + return 0; + + spin_lock_irqsave(&crash_count_lock, flags); + crash_count--; + pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", + lkdtm_crashpoint->name, lkdtm_crashtype->name, crash_count); + + if (crash_count == 0) { + do_it = true; + crash_count = cpoint_count; + } + spin_unlock_irqrestore(&crash_count_lock, flags); + + if (do_it) + lkdtm_do_action(lkdtm_crashtype); + + return 0; +} + +static ssize_t lkdtm_debugfs_entry(struct file *f, + const char __user *user_buf, + size_t count, loff_t *off) +{ + struct crashpoint *crashpoint = file_inode(f)->i_private; + const struct crashtype *crashtype = NULL; + char *buf; + int err; + + if (count >= PAGE_SIZE) + return -EINVAL; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, user_buf, count)) { + free_page((unsigned long) buf); + return -EFAULT; + } + /* NULL-terminate and remove enter */ + buf[count] = '\0'; + strim(buf); + + crashtype = find_crashtype(buf); + free_page((unsigned long)buf); + + if (!crashtype) + return -EINVAL; + + err = lkdtm_register_cpoint(crashpoint, crashtype); + if (err < 0) + return err; + + *off += count; + + return count; +} +#endif + +/* Generic read callback that just prints out the available crash types */ +static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, + size_t count, loff_t *off) +{ + char *buf; + int i, n, out; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); + for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { + n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", + crashtypes[i].name); + } + buf[n] = '\0'; + + out = simple_read_from_buffer(user_buf, count, off, + buf, n); + free_page((unsigned long) buf); + + return out; +} + +static int lkdtm_debugfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + +/* Special entry to just crash directly. Available without KPROBEs */ +static ssize_t direct_entry(struct file *f, const char __user *user_buf, + size_t count, loff_t *off) +{ + const struct crashtype *crashtype; + char *buf; + + if (count >= PAGE_SIZE) + return -EINVAL; + if (count < 1) + return -EINVAL; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, user_buf, count)) { + free_page((unsigned long) buf); + return -EFAULT; + } + /* NULL-terminate and remove enter */ + buf[count] = '\0'; + strim(buf); + + crashtype = find_crashtype(buf); + free_page((unsigned long) buf); + if (!crashtype) + return -EINVAL; + + pr_info("Performing direct entry %s\n", crashtype->name); + lkdtm_do_action(crashtype); + *off += count; + + return count; +} + +static struct dentry *lkdtm_debugfs_root; + +static int __init lkdtm_module_init(void) +{ + struct crashpoint *crashpoint = NULL; + const struct crashtype *crashtype = NULL; + int ret = -EINVAL; + int i; + + /* Neither or both of these need to be set */ + if ((cpoint_type || cpoint_name) && !(cpoint_type && cpoint_name)) { + pr_err("Need both cpoint_type and cpoint_name or neither\n"); + return -EINVAL; + } + + if (cpoint_type) { + crashtype = find_crashtype(cpoint_type); + if (!crashtype) { + pr_err("Unknown crashtype '%s'\n", cpoint_type); + return -EINVAL; + } + } + + if (cpoint_name) { + for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { + if (!strcmp(cpoint_name, crashpoints[i].name)) + crashpoint = &crashpoints[i]; + } + + /* Refuse unknown crashpoints. */ + if (!crashpoint) { + pr_err("Invalid crashpoint %s\n", cpoint_name); + return -EINVAL; + } + } + +#ifdef CONFIG_KPROBES + /* Set crash count. */ + crash_count = cpoint_count; +#endif + + /* Handle test-specific initialization. */ + lkdtm_bugs_init(&recur_count); + lkdtm_perms_init(); + lkdtm_usercopy_init(); + + /* Register debugfs interface */ + lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); + if (!lkdtm_debugfs_root) { + pr_err("creating root dir failed\n"); + return -ENODEV; + } + + /* Install debugfs trigger files. */ + for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { + struct crashpoint *cur = &crashpoints[i]; + struct dentry *de; + + de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, + cur, &cur->fops); + if (de == NULL) { + pr_err("could not create crashpoint %s\n", cur->name); + goto out_err; + } + } + + /* Install crashpoint if one was selected. */ + if (crashpoint) { + ret = lkdtm_register_cpoint(crashpoint, crashtype); + if (ret < 0) { + pr_info("Invalid crashpoint %s\n", crashpoint->name); + goto out_err; + } + pr_info("Crash point %s of type %s registered\n", + crashpoint->name, cpoint_type); + } else { + pr_info("No crash points registered, enable through debugfs\n"); + } + + return 0; + +out_err: + debugfs_remove_recursive(lkdtm_debugfs_root); + return ret; +} + +static void __exit lkdtm_module_exit(void) +{ + debugfs_remove_recursive(lkdtm_debugfs_root); + + /* Handle test-specific clean-up. */ + lkdtm_usercopy_exit(); + + if (lkdtm_kprobe != NULL) + unregister_kprobe(lkdtm_kprobe); + + pr_info("Crash point unregistered\n"); +} + +module_init(lkdtm_module_init); +module_exit(lkdtm_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Kernel crash testing module"); diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c new file mode 100644 index 0000000000000000000000000000000000000000..65026d7de1307d32b9e060358dadcc04ef0bdf56 --- /dev/null +++ b/drivers/misc/lkdtm/heap.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests relating directly to heap memory, including + * page allocation and slab allocations. + */ +#include "lkdtm.h" +#include +#include + +/* + * This tries to stay within the next largest power-of-2 kmalloc cache + * to avoid actually overwriting anything important if it's not detected + * correctly. + */ +void lkdtm_OVERWRITE_ALLOCATION(void) +{ + size_t len = 1020; + u32 *data = kmalloc(len, GFP_KERNEL); + if (!data) + return; + + data[1024 / sizeof(u32)] = 0x12345678; + kfree(data); +} + +void lkdtm_WRITE_AFTER_FREE(void) +{ + int *base, *again; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + if (!base) + return; + pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); + pr_info("Attempting bad write to freed memory at %p\n", + &base[offset]); + kfree(base); + base[offset] = 0x0abcdef0; + /* Attempt to notice the overwrite. */ + again = kmalloc(len, GFP_KERNEL); + kfree(again); + if (again != base) + pr_info("Hmm, didn't get the same memory range.\n"); +} + +void lkdtm_READ_AFTER_FREE(void) +{ + int *base, *val, saw; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + if (!base) { + pr_info("Unable to allocate base memory.\n"); + return; + } + + val = kmalloc(len, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate val memory.\n"); + kfree(base); + return; + } + + *val = 0x12345678; + base[offset] = *val; + pr_info("Value in memory before free: %x\n", base[offset]); + + kfree(base); + + pr_info("Attempting bad read from freed memory\n"); + saw = base[offset]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Memory was not poisoned\n"); + + kfree(val); +} + +void lkdtm_WRITE_BUDDY_AFTER_FREE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + if (!p) { + pr_info("Unable to allocate free page\n"); + return; + } + + pr_info("Writing to the buddy page before free\n"); + memset((void *)p, 0x3, PAGE_SIZE); + free_page(p); + schedule(); + pr_info("Attempting bad write to the buddy page after free\n"); + memset((void *)p, 0x78, PAGE_SIZE); + /* Attempt to notice the overwrite. */ + p = __get_free_page(GFP_KERNEL); + free_page(p); + schedule(); +} + +void lkdtm_READ_BUDDY_AFTER_FREE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + int saw, *val; + int *base; + + if (!p) { + pr_info("Unable to allocate free page\n"); + return; + } + + val = kmalloc(1024, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate val memory.\n"); + free_page(p); + return; + } + + base = (int *)p; + + *val = 0x12345678; + base[0] = *val; + pr_info("Value in memory before free: %x\n", base[0]); + free_page(p); + pr_info("Attempting to read from freed memory\n"); + saw = base[0]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Buddy page was not poisoned\n"); + + kfree(val); +} diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h new file mode 100644 index 0000000000000000000000000000000000000000..9e513dcfd8093613dd767765829158aa3addc810 --- /dev/null +++ b/drivers/misc/lkdtm/lkdtm.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LKDTM_H +#define __LKDTM_H + +#define pr_fmt(fmt) "lkdtm: " fmt + +#include + +/* lkdtm_bugs.c */ +void __init lkdtm_bugs_init(int *recur_param); +void lkdtm_PANIC(void); +void lkdtm_BUG(void); +void lkdtm_WARNING(void); +void lkdtm_EXCEPTION(void); +void lkdtm_LOOP(void); +void lkdtm_OVERFLOW(void); +void lkdtm_CORRUPT_STACK(void); +void lkdtm_CORRUPT_STACK_STRONG(void); +void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void); +void lkdtm_SOFTLOCKUP(void); +void lkdtm_HARDLOCKUP(void); +void lkdtm_SPINLOCKUP(void); +void lkdtm_HUNG_TASK(void); +void lkdtm_CORRUPT_LIST_ADD(void); +void lkdtm_CORRUPT_LIST_DEL(void); +void lkdtm_CORRUPT_USER_DS(void); +void lkdtm_STACK_GUARD_PAGE_LEADING(void); +void lkdtm_STACK_GUARD_PAGE_TRAILING(void); + +/* lkdtm_heap.c */ +void lkdtm_OVERWRITE_ALLOCATION(void); +void lkdtm_WRITE_AFTER_FREE(void); +void lkdtm_READ_AFTER_FREE(void); +void lkdtm_WRITE_BUDDY_AFTER_FREE(void); +void lkdtm_READ_BUDDY_AFTER_FREE(void); + +/* lkdtm_perms.c */ +void __init lkdtm_perms_init(void); +void lkdtm_WRITE_RO(void); +void lkdtm_WRITE_RO_AFTER_INIT(void); +void lkdtm_WRITE_KERN(void); +void lkdtm_EXEC_DATA(void); +void lkdtm_EXEC_STACK(void); +void lkdtm_EXEC_KMALLOC(void); +void lkdtm_EXEC_VMALLOC(void); +void lkdtm_EXEC_RODATA(void); +void lkdtm_EXEC_USERSPACE(void); +void lkdtm_ACCESS_USERSPACE(void); + +/* lkdtm_refcount.c */ +void lkdtm_REFCOUNT_INC_OVERFLOW(void); +void lkdtm_REFCOUNT_ADD_OVERFLOW(void); +void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void); +void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void); +void lkdtm_REFCOUNT_DEC_ZERO(void); +void lkdtm_REFCOUNT_DEC_NEGATIVE(void); +void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void); +void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void); +void lkdtm_REFCOUNT_INC_ZERO(void); +void lkdtm_REFCOUNT_ADD_ZERO(void); +void lkdtm_REFCOUNT_INC_SATURATED(void); +void lkdtm_REFCOUNT_DEC_SATURATED(void); +void lkdtm_REFCOUNT_ADD_SATURATED(void); +void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void); +void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void); +void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void); +void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void); +void lkdtm_REFCOUNT_TIMING(void); +void lkdtm_ATOMIC_TIMING(void); + +/* lkdtm_rodata.c */ +void lkdtm_rodata_do_nothing(void); + +/* lkdtm_usercopy.c */ +void __init lkdtm_usercopy_init(void); +void __exit lkdtm_usercopy_exit(void); +void lkdtm_USERCOPY_HEAP_SIZE_TO(void); +void lkdtm_USERCOPY_HEAP_SIZE_FROM(void); +void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void); +void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void); +void lkdtm_USERCOPY_STACK_FRAME_TO(void); +void lkdtm_USERCOPY_STACK_FRAME_FROM(void); +void lkdtm_USERCOPY_STACK_BEYOND(void); +void lkdtm_USERCOPY_KERNEL(void); + +#endif diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c new file mode 100644 index 0000000000000000000000000000000000000000..53b85c9d16b89247d0fa66d0dce5192d71f9c63e --- /dev/null +++ b/drivers/misc/lkdtm/perms.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests related to validating kernel memory + * permissions: non-executable regions, non-writable regions, and + * even non-readable regions. + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include + +/* Whether or not to fill the target memory area with do_nothing(). */ +#define CODE_WRITE true +#define CODE_AS_IS false + +/* How many bytes to copy to be sure we've copied enough of do_nothing(). */ +#define EXEC_SIZE 64 + +/* This is non-const, so it will end up in the .data section. */ +static u8 data_area[EXEC_SIZE]; + +/* This is cost, so it will end up in the .rodata section. */ +static const unsigned long rodata = 0xAA55AA55; + +/* This is marked __ro_after_init, so it should ultimately be .rodata. */ +static unsigned long ro_after_init __ro_after_init = 0x55AA5500; + +/* + * This just returns to the caller. It is designed to be copied into + * non-executable memory regions. + */ +static void do_nothing(void) +{ + return; +} + +/* Must immediately follow do_nothing for size calculuations to work out. */ +static void do_overwritten(void) +{ + pr_info("do_overwritten wasn't overwritten!\n"); + return; +} + +static noinline void execute_location(void *dst, bool write) +{ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + if (write == CODE_WRITE) { + memcpy(dst, do_nothing, EXEC_SIZE); + flush_icache_range((unsigned long)dst, + (unsigned long)dst + EXEC_SIZE); + } + pr_info("attempting bad execution at %p\n", func); + func(); +} + +static void execute_user_location(void *dst) +{ + int copied; + + /* Intentionally crossing kernel/user memory boundary. */ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + copied = access_process_vm(current, (unsigned long)dst, do_nothing, + EXEC_SIZE, FOLL_WRITE); + if (copied < EXEC_SIZE) + return; + pr_info("attempting bad execution at %p\n", func); + func(); +} + +void lkdtm_WRITE_RO(void) +{ + /* Explicitly cast away "const" for the test. */ + unsigned long *ptr = (unsigned long *)&rodata; + + pr_info("attempting bad rodata write at %p\n", ptr); + *ptr ^= 0xabcd1234; +} + +void lkdtm_WRITE_RO_AFTER_INIT(void) +{ + unsigned long *ptr = &ro_after_init; + + /* + * Verify we were written to during init. Since an Oops + * is considered a "success", a failure is to just skip the + * real test. + */ + if ((*ptr & 0xAA) != 0xAA) { + pr_info("%p was NOT written during init!?\n", ptr); + return; + } + + pr_info("attempting bad ro_after_init write at %p\n", ptr); + *ptr ^= 0xabcd1234; +} + +void lkdtm_WRITE_KERN(void) +{ + size_t size; + unsigned char *ptr; + + size = (unsigned long)do_overwritten - (unsigned long)do_nothing; + ptr = (unsigned char *)do_overwritten; + + pr_info("attempting bad %zu byte write at %p\n", size, ptr); + memcpy(ptr, (unsigned char *)do_nothing, size); + flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); + + do_overwritten(); +} + +void lkdtm_EXEC_DATA(void) +{ + execute_location(data_area, CODE_WRITE); +} + +void lkdtm_EXEC_STACK(void) +{ + u8 stack_area[EXEC_SIZE]; + execute_location(stack_area, CODE_WRITE); +} + +void lkdtm_EXEC_KMALLOC(void) +{ + u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); + execute_location(kmalloc_area, CODE_WRITE); + kfree(kmalloc_area); +} + +void lkdtm_EXEC_VMALLOC(void) +{ + u32 *vmalloc_area = vmalloc(EXEC_SIZE); + execute_location(vmalloc_area, CODE_WRITE); + vfree(vmalloc_area); +} + +void lkdtm_EXEC_RODATA(void) +{ + execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS); +} + +void lkdtm_EXEC_USERSPACE(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + execute_user_location((void *)user_addr); + vm_munmap(user_addr, PAGE_SIZE); +} + +void lkdtm_ACCESS_USERSPACE(void) +{ + unsigned long user_addr, tmp = 0; + unsigned long *ptr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { + pr_warn("copy_to_user failed\n"); + vm_munmap(user_addr, PAGE_SIZE); + return; + } + + ptr = (unsigned long *)user_addr; + + pr_info("attempting bad read at %p\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %p\n", ptr); + *ptr = tmp; + + vm_munmap(user_addr, PAGE_SIZE); +} + +void __init lkdtm_perms_init(void) +{ + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + +} diff --git a/drivers/misc/lkdtm/refcount.c b/drivers/misc/lkdtm/refcount.c new file mode 100644 index 0000000000000000000000000000000000000000..7d8dd368576345f847bf208b6615cddc9bc0d60f --- /dev/null +++ b/drivers/misc/lkdtm/refcount.c @@ -0,0 +1,392 @@ +/* + * This is for all the tests related to refcount bugs (e.g. overflow, + * underflow, reaching zero untested, etc). + */ +#include "lkdtm.h" +#include + +static void overflow_check(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Overflow detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Overflow detected: unsafely reset to max\n"); + break; + default: + pr_err("Fail: refcount wrapped to %d\n", refcount_read(ref)); + } +} + +/* + * A refcount_inc() above the maximum value of the refcount implementation, + * should at least saturate, and at most also WARN. + */ +void lkdtm_REFCOUNT_INC_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1); + + pr_info("attempting good refcount_inc() without overflow\n"); + refcount_dec(&over); + refcount_inc(&over); + + pr_info("attempting bad refcount_inc() overflow\n"); + refcount_inc(&over); + refcount_inc(&over); + + overflow_check(&over); +} + +/* refcount_add() should behave just like refcount_inc() above. */ +void lkdtm_REFCOUNT_ADD_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1); + + pr_info("attempting good refcount_add() without overflow\n"); + refcount_dec(&over); + refcount_dec(&over); + refcount_dec(&over); + refcount_dec(&over); + refcount_add(4, &over); + + pr_info("attempting bad refcount_add() overflow\n"); + refcount_add(4, &over); + + overflow_check(&over); +} + +/* refcount_inc_not_zero() should behave just like refcount_inc() above. */ +void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX); + + pr_info("attempting bad refcount_inc_not_zero() overflow\n"); + if (!refcount_inc_not_zero(&over)) + pr_warn("Weird: refcount_inc_not_zero() reported zero\n"); + + overflow_check(&over); +} + +/* refcount_add_not_zero() should behave just like refcount_inc() above. */ +void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void) +{ + refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX); + + pr_info("attempting bad refcount_add_not_zero() overflow\n"); + if (!refcount_add_not_zero(6, &over)) + pr_warn("Weird: refcount_add_not_zero() reported zero\n"); + + overflow_check(&over); +} + +static void check_zero(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Zero detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Zero detected: unsafely reset to max\n"); + break; + case 0: + pr_warn("Still at zero: refcount_inc/add() must not inc-from-0\n"); + break; + default: + pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); + } +} + +/* + * A refcount_dec(), as opposed to a refcount_dec_and_test(), when it hits + * zero it should either saturate (when inc-from-zero isn't protected) + * or stay at zero (when inc-from-zero is protected) and should WARN for both. + */ +void lkdtm_REFCOUNT_DEC_ZERO(void) +{ + refcount_t zero = REFCOUNT_INIT(2); + + pr_info("attempting good refcount_dec()\n"); + refcount_dec(&zero); + + pr_info("attempting bad refcount_dec() to zero\n"); + refcount_dec(&zero); + + check_zero(&zero); +} + +static void check_negative(refcount_t *ref, int start) +{ + /* + * CONFIG_REFCOUNT_FULL refuses to move a refcount at all on an + * over-sub, so we have to track our starting position instead of + * looking only at zero-pinning. + */ + if (refcount_read(ref) == start) { + pr_warn("Still at %d: refcount_inc/add() must not inc-from-0\n", + start); + return; + } + + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Negative detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Negative detected: unsafely reset to max\n"); + break; + default: + pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); + } +} + +/* A refcount_dec() going negative should saturate and may WARN. */ +void lkdtm_REFCOUNT_DEC_NEGATIVE(void) +{ + refcount_t neg = REFCOUNT_INIT(0); + + pr_info("attempting bad refcount_dec() below zero\n"); + refcount_dec(&neg); + + check_negative(&neg, 0); +} + +/* + * A refcount_dec_and_test() should act like refcount_dec() above when + * going negative. + */ +void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void) +{ + refcount_t neg = REFCOUNT_INIT(0); + + pr_info("attempting bad refcount_dec_and_test() below zero\n"); + if (refcount_dec_and_test(&neg)) + pr_warn("Weird: refcount_dec_and_test() reported zero\n"); + + check_negative(&neg, 0); +} + +/* + * A refcount_sub_and_test() should act like refcount_dec_and_test() + * above when going negative. + */ +void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void) +{ + refcount_t neg = REFCOUNT_INIT(3); + + pr_info("attempting bad refcount_sub_and_test() below zero\n"); + if (refcount_sub_and_test(5, &neg)) + pr_warn("Weird: refcount_sub_and_test() reported zero\n"); + + check_negative(&neg, 3); +} + +static void check_from_zero(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case 0: + pr_info("Zero detected: stayed at zero\n"); + break; + case REFCOUNT_SATURATED: + pr_info("Zero detected: saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Zero detected: unsafely reset to max\n"); + break; + default: + pr_info("Fail: zero not detected, incremented to %d\n", + refcount_read(ref)); + } +} + +/* + * A refcount_inc() from zero should pin to zero or saturate and may WARN. + * Only CONFIG_REFCOUNT_FULL provides this protection currently. + */ +void lkdtm_REFCOUNT_INC_ZERO(void) +{ + refcount_t zero = REFCOUNT_INIT(0); + + pr_info("attempting safe refcount_inc_not_zero() from zero\n"); + if (!refcount_inc_not_zero(&zero)) { + pr_info("Good: zero detected\n"); + if (refcount_read(&zero) == 0) + pr_info("Correctly stayed at zero\n"); + else + pr_err("Fail: refcount went past zero!\n"); + } else { + pr_err("Fail: Zero not detected!?\n"); + } + + pr_info("attempting bad refcount_inc() from zero\n"); + refcount_inc(&zero); + + check_from_zero(&zero); +} + +/* + * A refcount_add() should act like refcount_inc() above when starting + * at zero. + */ +void lkdtm_REFCOUNT_ADD_ZERO(void) +{ + refcount_t zero = REFCOUNT_INIT(0); + + pr_info("attempting safe refcount_add_not_zero() from zero\n"); + if (!refcount_add_not_zero(3, &zero)) { + pr_info("Good: zero detected\n"); + if (refcount_read(&zero) == 0) + pr_info("Correctly stayed at zero\n"); + else + pr_err("Fail: refcount went past zero\n"); + } else { + pr_err("Fail: Zero not detected!?\n"); + } + + pr_info("attempting bad refcount_add() from zero\n"); + refcount_add(3, &zero); + + check_from_zero(&zero); +} + +static void check_saturated(refcount_t *ref) +{ + switch (refcount_read(ref)) { + case REFCOUNT_SATURATED: + pr_info("Saturation detected: still saturated\n"); + break; + case REFCOUNT_MAX: + pr_warn("Saturation detected: unsafely reset to max\n"); + break; + default: + pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); + } +} + +/* + * A refcount_inc() from a saturated value should at most warn about + * being saturated already. + */ +void lkdtm_REFCOUNT_INC_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_inc() from saturated\n"); + refcount_inc(&sat); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_DEC_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_dec() from saturated\n"); + refcount_dec(&sat); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_ADD_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_dec() from saturated\n"); + refcount_add(8, &sat); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_inc_not_zero() from saturated\n"); + if (!refcount_inc_not_zero(&sat)) + pr_warn("Weird: refcount_inc_not_zero() reported zero\n"); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_add_not_zero() from saturated\n"); + if (!refcount_add_not_zero(7, &sat)) + pr_warn("Weird: refcount_add_not_zero() reported zero\n"); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_dec_and_test() from saturated\n"); + if (refcount_dec_and_test(&sat)) + pr_warn("Weird: refcount_dec_and_test() reported zero\n"); + + check_saturated(&sat); +} + +/* Should act like refcount_inc() above from saturated. */ +void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void) +{ + refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); + + pr_info("attempting bad refcount_sub_and_test() from saturated\n"); + if (refcount_sub_and_test(8, &sat)) + pr_warn("Weird: refcount_sub_and_test() reported zero\n"); + + check_saturated(&sat); +} + +/* Used to time the existing atomic_t when used for reference counting */ +void lkdtm_ATOMIC_TIMING(void) +{ + unsigned int i; + atomic_t count = ATOMIC_INIT(1); + + for (i = 0; i < INT_MAX - 1; i++) + atomic_inc(&count); + + for (i = INT_MAX; i > 0; i--) + if (atomic_dec_and_test(&count)) + break; + + if (i != 1) + pr_err("atomic timing: out of sync up/down cycle: %u\n", i - 1); + else + pr_info("atomic timing: done\n"); +} + +/* + * This can be compared to ATOMIC_TIMING when implementing fast refcount + * protections. Looking at the number of CPU cycles tells the real story + * about performance. For example: + * cd /sys/kernel/debug/provoke-crash + * perf stat -B -- cat <(echo REFCOUNT_TIMING) > DIRECT + */ +void lkdtm_REFCOUNT_TIMING(void) +{ + unsigned int i; + refcount_t count = REFCOUNT_INIT(1); + + for (i = 0; i < INT_MAX - 1; i++) + refcount_inc(&count); + + for (i = INT_MAX; i > 0; i--) + if (refcount_dec_and_test(&count)) + break; + + if (i != 1) + pr_err("refcount: out of sync up/down cycle: %u\n", i - 1); + else + pr_info("refcount timing: done\n"); +} diff --git a/drivers/misc/lkdtm/rodata.c b/drivers/misc/lkdtm/rodata.c new file mode 100644 index 0000000000000000000000000000000000000000..58d180af72cf0e3afd3f1a9459aef892cbc85eb3 --- /dev/null +++ b/drivers/misc/lkdtm/rodata.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This includes functions that are meant to live entirely in .rodata + * (via objcopy tricks), to validate the non-executability of .rodata. + */ +#include "lkdtm.h" + +void notrace lkdtm_rodata_do_nothing(void) +{ + /* Does nothing. We just want an architecture agnostic "return". */ +} diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c new file mode 100644 index 0000000000000000000000000000000000000000..9725aed305bbadad773c260dee8139f49fc093ca --- /dev/null +++ b/drivers/misc/lkdtm/usercopy.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is for all the tests related to copy_to_user() and copy_from_user() + * hardening. + */ +#include "lkdtm.h" +#include +#include +#include +#include +#include +#include + +/* + * Many of the tests here end up using const sizes, but those would + * normally be ignored by hardened usercopy, so force the compiler + * into choosing the non-const path to make sure we trigger the + * hardened usercopy checks by added "unconst" to all the const copies, + * and making sure "cache_size" isn't optimized into a const. + */ +static volatile size_t unconst = 0; +static volatile size_t cache_size = 1024; +static struct kmem_cache *whitelist_cache; + +static const unsigned char test_text[] = "This is a test.\n"; + +/* + * Instead of adding -Wno-return-local-addr, just pass the stack address + * through a function to obfuscate it from the compiler. + */ +static noinline unsigned char *trick_compiler(unsigned char *stack) +{ + return stack + 0; +} + +static noinline unsigned char *do_usercopy_stack_callee(int value) +{ + unsigned char buf[32]; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(buf); i++) { + buf[i] = value & 0xff; + } + + return trick_compiler(buf); +} + +static noinline void do_usercopy_stack(bool to_user, bool bad_frame) +{ + unsigned long user_addr; + unsigned char good_stack[32]; + unsigned char *bad_stack; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(good_stack); i++) + good_stack[i] = test_text[i % sizeof(test_text)]; + + /* This is a pointer to outside our current stack frame. */ + if (bad_frame) { + bad_stack = do_usercopy_stack_callee((uintptr_t)&bad_stack); + } else { + /* Put start address just inside stack. */ + bad_stack = task_stack_page(current) + THREAD_SIZE; + bad_stack -= sizeof(unsigned long); + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (to_user) { + pr_info("attempting good copy_to_user of local stack\n"); + if (copy_to_user((void __user *)user_addr, good_stack, + unconst + sizeof(good_stack))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of distant stack\n"); + if (copy_to_user((void __user *)user_addr, bad_stack, + unconst + sizeof(good_stack))) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + /* + * There isn't a safe way to not be protected by usercopy + * if we're going to write to another thread's stack. + */ + if (!bad_frame) + goto free_user; + + pr_info("attempting good copy_from_user of local stack\n"); + if (copy_from_user(good_stack, (void __user *)user_addr, + unconst + sizeof(good_stack))) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of distant stack\n"); + if (copy_from_user(bad_stack, (void __user *)user_addr, + unconst + sizeof(good_stack))) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +/* + * This checks for whole-object size validation with hardened usercopy, + * with or without usercopy whitelisting. + */ +static void do_usercopy_heap_size(bool to_user) +{ + unsigned long user_addr; + unsigned char *one, *two; + void __user *test_user_addr; + void *test_kern_addr; + size_t size = unconst + 1024; + + one = kmalloc(size, GFP_KERNEL); + two = kmalloc(size, GFP_KERNEL); + if (!one || !two) { + pr_warn("Failed to allocate kernel memory\n"); + goto free_kernel; + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_kernel; + } + + memset(one, 'A', size); + memset(two, 'B', size); + + test_user_addr = (void __user *)(user_addr + 16); + test_kern_addr = one + 16; + + if (to_user) { + pr_info("attempting good copy_to_user of correct size\n"); + if (copy_to_user(test_user_addr, test_kern_addr, size / 2)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of too large size\n"); + if (copy_to_user(test_user_addr, test_kern_addr, size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user of correct size\n"); + if (copy_from_user(test_kern_addr, test_user_addr, size / 2)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of too large size\n"); + if (copy_from_user(test_kern_addr, test_user_addr, size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +free_kernel: + kfree(one); + kfree(two); +} + +/* + * This checks for the specific whitelist window within an object. If this + * test passes, then do_usercopy_heap_size() tests will pass too. + */ +static void do_usercopy_heap_whitelist(bool to_user) +{ + unsigned long user_alloc; + unsigned char *buf = NULL; + unsigned char __user *user_addr; + size_t offset, size; + + /* Make sure cache was prepared. */ + if (!whitelist_cache) { + pr_warn("Failed to allocate kernel cache\n"); + return; + } + + /* + * Allocate a buffer with a whitelisted window in the buffer. + */ + buf = kmem_cache_alloc(whitelist_cache, GFP_KERNEL); + if (!buf) { + pr_warn("Failed to allocate buffer from whitelist cache\n"); + goto free_alloc; + } + + /* Allocate user memory we'll poke at. */ + user_alloc = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_alloc >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_alloc; + } + user_addr = (void __user *)user_alloc; + + memset(buf, 'B', cache_size); + + /* Whitelisted window in buffer, from kmem_cache_create_usercopy. */ + offset = (cache_size / 4) + unconst; + size = (cache_size / 16) + unconst; + + if (to_user) { + pr_info("attempting good copy_to_user inside whitelist\n"); + if (copy_to_user(user_addr, buf + offset, size)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user outside whitelist\n"); + if (copy_to_user(user_addr, buf + offset - 1, size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user inside whitelist\n"); + if (copy_from_user(buf + offset, user_addr, size)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user outside whitelist\n"); + if (copy_from_user(buf + offset - 1, user_addr, size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_alloc, PAGE_SIZE); +free_alloc: + if (buf) + kmem_cache_free(whitelist_cache, buf); +} + +/* Callable tests. */ +void lkdtm_USERCOPY_HEAP_SIZE_TO(void) +{ + do_usercopy_heap_size(true); +} + +void lkdtm_USERCOPY_HEAP_SIZE_FROM(void) +{ + do_usercopy_heap_size(false); +} + +void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void) +{ + do_usercopy_heap_whitelist(true); +} + +void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void) +{ + do_usercopy_heap_whitelist(false); +} + +void lkdtm_USERCOPY_STACK_FRAME_TO(void) +{ + do_usercopy_stack(true, true); +} + +void lkdtm_USERCOPY_STACK_FRAME_FROM(void) +{ + do_usercopy_stack(false, true); +} + +void lkdtm_USERCOPY_STACK_BEYOND(void) +{ + do_usercopy_stack(true, false); +} + +void lkdtm_USERCOPY_KERNEL(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + pr_info("attempting good copy_to_user from kernel rodata\n"); + if (copy_to_user((void __user *)user_addr, test_text, + unconst + sizeof(test_text))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user from kernel text\n"); + if (copy_to_user((void __user *)user_addr, vm_mmap, + unconst + PAGE_SIZE)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +void __init lkdtm_usercopy_init(void) +{ + /* Prepare cache that lacks SLAB_USERCOPY flag. */ + whitelist_cache = + kmem_cache_create_usercopy("lkdtm-usercopy", cache_size, + 0, 0, + cache_size / 4, + cache_size / 16, + NULL); +} + +void __exit lkdtm_usercopy_exit(void) +{ + kmem_cache_destroy(whitelist_cache); +} diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 3a8c7532ee0d23ed1e896fe94ff017e9cbb82738..754565a8a2fcab046d0e15e460d47c1b7e4acc95 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -32,39 +32,12 @@ #include #include #include +#include /* A unified ethernet device probe. This is the easiest way to have every ethernet adaptor have the name "eth[0123...]". */ -extern struct net_device *hp100_probe(int unit); -extern struct net_device *ultra_probe(int unit); -extern struct net_device *wd_probe(int unit); -extern struct net_device *ne_probe(int unit); -extern struct net_device *fmv18x_probe(int unit); -extern struct net_device *i82596_probe(int unit); -extern struct net_device *ni65_probe(int unit); -extern struct net_device *sonic_probe(int unit); -extern struct net_device *smc_init(int unit); -extern struct net_device *atarilance_probe(int unit); -extern struct net_device *sun3lance_probe(int unit); -extern struct net_device *sun3_82586_probe(int unit); -extern struct net_device *apne_probe(int unit); -extern struct net_device *cs89x0_probe(int unit); -extern struct net_device *mvme147lance_probe(int unit); -extern struct net_device *tc515_probe(int unit); -extern struct net_device *lance_probe(int unit); -extern struct net_device *mac8390_probe(int unit); -extern struct net_device *mac89x0_probe(int unit); -extern struct net_device *cops_probe(int unit); -extern struct net_device *ltpc_probe(void); - -/* Fibre Channel adapters */ -extern int iph5526_probe(struct net_device *dev); - -/* SBNI adapters */ -extern int sbni_probe(int unit); - struct devprobe2 { struct net_device *(*probe)(int unit); int status; /* non-zero if autoprobe has failed */ diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 284d751ea97fb37d5ea934593ff1473fdbdbe744..cd5219a8f10cbdd0a5e918bcc65f48a70c5d468e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -474,7 +474,7 @@ void can_bus_off(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - netdev_dbg(dev, "bus-off\n"); + netdev_info(dev, "bus-off\n"); netif_carrier_off(dev); priv->can_stats.bus_off++; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 732a8ed571c28f66cc6def34074a3489c3a9f939..c2d0559115d321b3dbd7e421b5c725c3b0a90c0e 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -187,9 +187,6 @@ static void sja1000_start(struct net_device *dev) /* clear interrupt flags */ priv->read_reg(priv, SJA1000_IR); - /* clear interrupt flags */ - priv->read_reg(priv, SJA1000_IR); - /* leave reset mode */ set_normal_mode(dev); } diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index d921416295ceb2c2f647a7dfc97da9c88506cbad..188d3b2b1cf832f1537d6e43cc70d46f271d0d69 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1081,6 +1081,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) usb_free_urb(dev->intr_urb); kfree(dev->intr_in_buffer); + kfree(dev->tx_msg_buffer); } } diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index a3fb8b51038a17ae5d4ec3989c942afee4644ca9..07b8d8b3dbb26888986b1b56d87a1fc511c46b45 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -834,7 +834,7 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, skb = alloc_can_skb(priv->netdev, &cf); if (!skb) { - stats->tx_dropped++; + stats->rx_dropped++; return; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9be91cb4f4a305c64996ab6e4aeb31d94af547b6..99843f6b501dc08a5a8e7843fc3f575b4c986eba 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -594,7 +594,10 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; - if (!vlan->port->passthru) + /* Support unicast filter only on passthru devices. + * Multicast filter should be allowed on all devices. + */ + if (!vlan->port->passthru && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) @@ -612,7 +615,10 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; - if (!vlan->port->passthru) + /* Support unicast filter only on passthru devices. + * Multicast filter should be allowed on all devices. + */ + if (!vlan->port->passthru && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index f25f47853dd6c1e4e28657886a75f4d04429f04f..e921214eef95397f61d5d323c3751cc2d6941627 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -459,7 +460,7 @@ static inline struct sk_buff *macvtap_alloc_skb(struct sock *sk, size_t prepad, linear = len; skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, - err, 0); + err); if (!skb) return NULL; @@ -568,7 +569,11 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb, gso_type = SKB_GSO_TCPV6; break; case VIRTIO_NET_HDR_GSO_UDP: + pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n", + current->comm); gso_type = SKB_GSO_UDP; + if (skb->protocol == htons(ETH_P_IPV6)) + ipv6_proxy_select_ident(skb); break; default: return -EINVAL; @@ -613,8 +618,6 @@ static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb, vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (sinfo->gso_type & SKB_GSO_UDP) - vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (sinfo->gso_type & SKB_GSO_TCP_ECN) @@ -970,6 +973,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNSETSNDBUF: if (get_user(u, up)) return -EFAULT; + if (u <= 0) + return -EINVAL; q->sk.sk_sndbuf = u; return 0; @@ -992,7 +997,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | - TUN_F_TSO_ECN | TUN_F_UFO)) + TUN_F_TSO_ECN)) return -EINVAL; /* TODO: only accept frames with the features that diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 59ac143dec2576a697d9f383ef4d5d7372eef93c..fb9b7591571b7c13cf2956e80946da2702cba165 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -101,6 +101,7 @@ struct netconsole_target { struct config_item item; #endif int enabled; + struct mutex mutex; struct netpoll np; }; @@ -180,6 +181,7 @@ static struct netconsole_target *alloc_param_target(char *target_config) strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; + mutex_init(&nt->mutex); memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Parse parameters and setup netpoll */ @@ -307,6 +309,7 @@ static ssize_t store_enabled(struct netconsole_target *nt, const char *buf, size_t count) { + unsigned long flags; int enabled; int err; @@ -322,7 +325,6 @@ static ssize_t store_enabled(struct netconsole_target *nt, } if (enabled) { /* 1 */ - /* * Skip netpoll_parse_options() -- all the attributes are * already configured via configfs. Just print them out. @@ -334,8 +336,14 @@ static ssize_t store_enabled(struct netconsole_target *nt, return err; printk(KERN_INFO "netconsole: network logging started\n"); - } else { /* 0 */ + /* We need to disable the netconsole before cleaning it up + * otherwise we might end up in write_msg() with + * nt->np.dev == NULL and nt->enabled == 1 + */ + spin_lock_irqsave(&target_list_lock, flags); + nt->enabled = 0; + spin_unlock_irqrestore(&target_list_lock, flags); netpoll_cleanup(&nt->np); } @@ -556,8 +564,10 @@ static ssize_t netconsole_target_attr_store(struct config_item *item, struct netconsole_target_attr *na = container_of(attr, struct netconsole_target_attr, attr); + mutex_lock(&nt->mutex); if (na->store) ret = na->store(nt, buf, count); + mutex_unlock(&nt->mutex); return ret; } @@ -596,6 +606,7 @@ static struct config_item *make_netconsole_target(struct config_group *group, strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; + mutex_init(&nt->mutex); memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Initialize the config_item member */ @@ -677,12 +688,13 @@ restart: case NETDEV_RELEASE: case NETDEV_JOIN: case NETDEV_UNREGISTER: - /* - * rtnl_lock already held + /* rtnl_lock already held * we might sleep in __netpoll_cleanup() */ spin_unlock_irqrestore(&target_list_lock, flags); + __netpoll_cleanup(&nt->np); + spin_lock_irqsave(&target_list_lock, flags); dev_put(nt->np.dev); nt->np.dev = NULL; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index ab79c0f13d0aae45c81f2de75c1b08ce078bc220..ddc501deefbad803853d1764884010bd11c96939 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -892,6 +892,7 @@ static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn = net_generic(net, ppp_net_id); + mutex_destroy(&pn->all_ppp_mutex); idr_destroy(&pn->units_idr); } @@ -2872,6 +2873,15 @@ ppp_connect_channel(struct channel *pch, int unit) goto outl; ppp_lock(ppp); + spin_lock_bh(&pch->downl); + if (!pch->chan) { + /* Don't connect unregistered channels */ + spin_unlock_bh(&pch->downl); + ppp_unlock(ppp); + ret = -ENOTCONN; + goto outl; + } + spin_unlock_bh(&pch->downl); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 2840cf6083129d8c00f271af3e6245f4328fcbb2..c3db80d1b15ab3144fc47b2bf2deeefeefa059f8 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -613,6 +613,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppox)) + goto end; + if (sp->sa_protocol != PX_PROTO_OE) goto end; @@ -830,6 +834,7 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct pppoe_hdr *ph; struct net_device *dev; char *start; + int hlen; lock_sock(sk); if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { @@ -848,16 +853,16 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, if (total_len > (dev->mtu + dev->hard_header_len)) goto end; - - skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, - 0, GFP_KERNEL); + hlen = LL_RESERVED_SPACE(dev); + skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len + + dev->needed_tailroom, 0, GFP_KERNEL); if (!skb) { error = -ENOMEM; goto end; } /* Reserve space for headers. */ - skb_reserve(skb, dev->hard_header_len); + skb_reserve(skb, hlen); skb_reset_network_header(skb); skb->dev = dev; @@ -918,7 +923,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) /* Copy the data if there is no space for the header or if it's * read-only. */ - if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) + if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph))) goto abort; __skb_push(skb, sizeof(*ph)); diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 9a423435039ae8cfd3242ea198d9d8bdbf3fbbc9..3eb44cfae48c01575638e23a4ee0bc0f42f2451e 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -488,7 +488,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu = dst_mtu(&rt->dst); if (!po->chan.mtu) po->chan.mtu = PPP_MRU; - ip_rt_put(rt); po->chan.mtu -= PPTP_HEADER_OVERHEAD; po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 0a3ad7ba2bea4b81af240810cbb3b06c50496628..06d184c42cd5f56690583d1315a486a8410e4e2b 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -253,6 +253,17 @@ static void __team_option_inst_mark_removed_port(struct team *team, } } +static bool __team_option_inst_tmp_find(const struct list_head *opts, + const struct team_option_inst *needle) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, opts, tmp_list) + if (opt_inst == needle) + return true; + return false; +} + static int __team_options_register(struct team *team, const struct team_option *option, size_t option_count) @@ -863,7 +874,7 @@ static void team_port_disable(struct team *team, static void __team_compute_features(struct team *team) { struct team_port *port; - u32 vlan_features = TEAM_VLAN_FEATURES; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE; @@ -2158,7 +2169,7 @@ send_done: if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } @@ -2322,6 +2333,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) if (err) goto team_put; opt_inst->changed = true; + + /* dumb/evil user-space can send us duplicate opt, + * keep only the last one + */ + if (__team_option_inst_tmp_find(&opt_inst_list, + opt_inst)) + continue; + list_add(&opt_inst->tmp_list, &opt_inst_list); } if (!opt_found) { @@ -2438,7 +2457,7 @@ send_done: if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } @@ -2668,8 +2687,10 @@ static int team_device_event(struct notifier_block *unused, case NETDEV_UP: if (netif_carrier_ok(dev)) team_port_change_check(port, true); + break; case NETDEV_DOWN: team_port_change_check(port, false); + break; case NETDEV_CHANGE: if (netif_running(port->dev)) team_port_change_check(port, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 211df7e9edba00a929675ef933cf2d84a7f96e4b..f27c53006cb066a51f575aecc6645d6ab9386d24 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -60,14 +60,17 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include @@ -109,7 +112,7 @@ struct tap_filter { unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; }; -/* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for +/* DEFAULT_MAX_NUM_RSS_QUEUES were chosen to let the rx/tx queues allocated for * the netdevice to be fit in one page. So we can make sure the success of * memory allocation. TODO: increase the limit. */ #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES @@ -118,7 +121,7 @@ struct tap_filter { #define TUN_FLOW_EXPIRE (3 * HZ) /* A tun_file connects an open character device to a tuntap netdevice. It - * also contains all socket related strctures (except sock_fprog and tap_filter) + * also contains all socket related structures (except sock_fprog and tap_filter) * to serve as one transmit queue for tuntap device. The sock_fprog and * tap_filter were kept in tun_struct since they were used for filtering for the * netdevice not for a specific queue (at least I didn't see the requirement for @@ -137,7 +140,10 @@ struct tun_file { struct fasync_struct *fasync; /* only used for fasnyc */ unsigned int flags; - u16 queue_index; + union { + u16 queue_index; + unsigned int ifindex; + }; struct list_head next; struct tun_struct *detached; }; @@ -148,6 +154,7 @@ struct tun_flow_entry { struct tun_struct *tun; u32 rxhash; + u32 rps_rxhash; int queue_index; unsigned long updated; }; @@ -168,7 +175,7 @@ struct tun_struct { struct net_device *dev; netdev_features_t set_features; #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ - NETIF_F_TSO6|NETIF_F_UFO) + NETIF_F_TSO6) int vnet_hdr_sz; int sndbuf; @@ -216,6 +223,7 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun, rxhash, queue_index); e->updated = jiffies; e->rxhash = rxhash; + e->rps_rxhash = 0; e->queue_index = queue_index; e->tun = tun; hlist_add_head_rcu(&e->hash_link, head); @@ -228,6 +236,7 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) { tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n", e->rxhash, e->queue_index); + sock_rps_reset_flow_hash(e->rps_rxhash); hlist_del_rcu(&e->hash_link); kfree_rcu(e, rcu); --tun->flow_count; @@ -275,25 +284,28 @@ static void tun_flow_cleanup(unsigned long data) tun_debug(KERN_INFO, tun, "tun_flow_cleanup\n"); - spin_lock_bh(&tun->lock); + spin_lock(&tun->lock); for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) { struct tun_flow_entry *e; struct hlist_node *n; hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) { unsigned long this_timer; - count++; + this_timer = e->updated + delay; - if (time_before_eq(this_timer, jiffies)) + if (time_before_eq(this_timer, jiffies)) { tun_flow_delete(tun, e); - else if (time_before(this_timer, next_timer)) + continue; + } + count++; + if (time_before(this_timer, next_timer)) next_timer = this_timer; } } if (count) mod_timer(&tun->flow_gc_timer, round_jiffies_up(next_timer)); - spin_unlock_bh(&tun->lock); + spin_unlock(&tun->lock); } static void tun_flow_update(struct tun_struct *tun, u32 rxhash, @@ -321,6 +333,7 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash, /* TODO: keep queueing to old queue until it's empty? */ e->queue_index = queue_index; e->updated = jiffies; + sock_rps_record_flow_hash(e->rps_rxhash); } else { spin_lock_bh(&tun->lock); if (!tun_flow_find(head, rxhash) && @@ -337,8 +350,20 @@ unlock: rcu_read_unlock(); } +/** + * Save the hash received in the stack receive path and update the + * flow_hash table accordingly. + */ +static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) +{ + if (unlikely(e->rps_rxhash != hash)) { + sock_rps_reset_flow_hash(e->rps_rxhash); + e->rps_rxhash = hash; + } +} + /* We try to identify a flow through its rxhash first. The reason that - * we do not check rxq no. is becuase some cards(e.g 82599), chooses + * we do not check rxq no. is because some cards(e.g 82599), chooses * the rxq based on the txq where the last packet of the flow comes. As * the userspace application move between processors, we may get a * different rxq no. here. If we could not get rxhash, then we would @@ -357,9 +382,10 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb) txq = skb_get_rxhash(skb); if (txq) { e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); - if (e) + if (e) { + tun_flow_save_rps_rxhash(e, txq); txq = e->queue_index; - else + } else /* use multiply and shift instead of expensive divide */ txq = ((u64)txq * numqueues) >> 32; } else if (likely(skb_rx_queue_recorded(skb))) { @@ -405,6 +431,12 @@ static struct tun_struct *tun_enable_queue(struct tun_file *tfile) return tun; } +static void tun_queue_purge(struct tun_file *tfile) +{ + skb_queue_purge(&tfile->sk.sk_receive_queue); + skb_queue_purge(&tfile->sk.sk_error_queue); +} + static void __tun_detach(struct tun_file *tfile, bool clean) { struct tun_file *ntfile; @@ -423,7 +455,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) --tun->numqueues; if (clean) { - rcu_assign_pointer(tfile->tun, NULL); + RCU_INIT_POINTER(tfile->tun, NULL); sock_put(&tfile->sk); } else tun_disable_queue(tun, tfile); @@ -431,7 +463,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) synchronize_net(); tun_flow_delete_by_queue(tun, tun->numqueues + 1); /* Drop read queue */ - skb_queue_purge(&tfile->sk.sk_receive_queue); + tun_queue_purge(tfile); tun_set_real_num_queues(tun); } else if (tfile->detached && clean) { tun = tun_enable_queue(tfile); @@ -469,13 +501,15 @@ static void tun_detach_all(struct net_device *dev) for (i = 0; i < n; i++) { tfile = rtnl_dereference(tun->tfiles[i]); BUG_ON(!tfile); - wake_up_all(&tfile->wq.wait); - rcu_assign_pointer(tfile->tun, NULL); + tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN; + tfile->socket.sk->sk_data_ready((tfile->socket.sk),0); + RCU_INIT_POINTER(tfile->tun, NULL); --tun->numqueues; } list_for_each_entry(tfile, &tun->disabled, next) { - wake_up_all(&tfile->wq.wait); - rcu_assign_pointer(tfile->tun, NULL); + tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN; + tfile->socket.sk->sk_data_ready((tfile->socket.sk),0); + RCU_INIT_POINTER(tfile->tun, NULL); } BUG_ON(tun->numqueues != 0); @@ -483,12 +517,12 @@ static void tun_detach_all(struct net_device *dev) for (i = 0; i < n; i++) { tfile = rtnl_dereference(tun->tfiles[i]); /* Drop read queue */ - skb_queue_purge(&tfile->sk.sk_receive_queue); + tun_queue_purge(tfile); sock_put(&tfile->sk); } list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { tun_enable_queue(tfile); - skb_queue_purge(&tfile->sk.sk_receive_queue); + tun_queue_purge(tfile); sock_put(&tfile->sk); } BUG_ON(tun->numdisabled != 0); @@ -497,7 +531,7 @@ static void tun_detach_all(struct net_device *dev) module_put(THIS_MODULE); } -static int tun_attach(struct tun_struct *tun, struct file *file) +static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter) { struct tun_file *tfile = file->private_data; int err; @@ -521,13 +555,14 @@ static int tun_attach(struct tun_struct *tun, struct file *file) err = 0; - /* Re-attach the filter to presist device */ - if (tun->filter_attached == true) { + /* Re-attach the filter to persist device */ + if (!skip_filter && (tun->filter_attached == true)) { err = sk_attach_filter(&tun->fprog, tfile->socket.sk); if (!err) goto out; } tfile->queue_index = tun->numqueues; + tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; rcu_assign_pointer(tfile->tun, tun); rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); tun->numqueues++; @@ -599,14 +634,9 @@ static int update_filter(struct tap_filter *filter, void __user *arg) } alen = ETH_ALEN * uf.count; - addr = kmalloc(alen, GFP_KERNEL); - if (!addr) - return -ENOMEM; - - if (copy_from_user(addr, arg + sizeof(uf), alen)) { - err = -EFAULT; - goto done; - } + addr = memdup_user(arg + sizeof(uf), alen); + if (IS_ERR(addr)) + return PTR_ERR(addr); /* The filter is updated without holding any locks. Which is * perfectly safe. We disable it first and in the worst @@ -626,7 +656,7 @@ static int update_filter(struct tap_filter *filter, void __user *arg) for (; n < uf.count; n++) { if (!is_multicast_ether_addr(addr[n].u)) { err = 0; /* no filter */ - goto done; + goto free_addr; } addr_hash_set(filter->mask, addr[n].u); } @@ -642,8 +672,7 @@ static int update_filter(struct tap_filter *filter, void __user *arg) /* Return the number of exact filters */ err = nexact; - -done: +free_addr: kfree(addr); return err; } @@ -710,14 +739,34 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) struct tun_struct *tun = netdev_priv(dev); int txq = skb->queue_mapping; struct tun_file *tfile; + u32 numqueues = 0; rcu_read_lock(); tfile = rcu_dereference(tun->tfiles[txq]); + numqueues = ACCESS_ONCE(tun->numqueues); /* Drop packet if interface is not attached */ - if (txq >= tun->numqueues) + if (txq >= numqueues) goto drop; +#ifdef CONFIG_RPS + if (numqueues == 1 && static_key_false(&rps_needed)) { + /* Select queue was not called for the skbuff, so we extract the + * RPS hash and save it into the flow_table here. + */ + __u32 rxhash; + + rxhash = skb_get_rxhash(skb); + if (rxhash) { + struct tun_flow_entry *e; + e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], + rxhash); + if (e) + tun_flow_save_rps_rxhash(e, rxhash); + } + } +#endif + tun_debug(KERN_INFO, tun, "tun_net_xmit %d\n", skb->len); BUG_ON(!tfile); @@ -735,14 +784,18 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* Limit the number of packets queued by dividing txq length with the * number of queues. */ - if (skb_queue_len(&tfile->socket.sk->sk_receive_queue) - >= dev->tx_queue_len / tun->numqueues) + if (skb_queue_len(&tfile->socket.sk->sk_receive_queue) * numqueues + >= dev->tx_queue_len) goto drop; - /* Orphan the skb - required as we might hang on to it - * for indefinite time. */ if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) goto drop; + + skb_tx_timestamp(skb); + + /* Orphan the skb - required as we might hang on to it + * for indefinite time. + */ skb_orphan(skb); nf_reset(skb); @@ -753,8 +806,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* Notify and wake up reader process */ if (tfile->flags & TUN_FASYNC) kill_fasync(&tfile->fasync, SIGIO, POLL_IN); - wake_up_interruptible_poll(&tfile->wq.wait, POLLIN | - POLLRDNORM | POLLRDBAND); + tfile->socket.sk->sk_data_ready((tfile->socket.sk),0); rcu_read_unlock(); return NETDEV_TX_OK; @@ -802,9 +854,9 @@ static void tun_poll_controller(struct net_device *dev) * Tun only receives frames when: * 1) the char device endpoint gets data from user space * 2) the tun socket gets a sendmsg call from user space - * Since both of those are syncronous operations, we are guaranteed + * Since both of those are synchronous operations, we are guaranteed * never to have pending data when we poll for it - * so theres nothing to do here but return. + * so there is nothing to do here but return. * We need this though so netpoll recognizes us as an interface that * supports polling, which enables bridge devices in virt setups to * still use netconsole @@ -841,7 +893,7 @@ static const struct net_device_ops tap_netdev_ops = { #endif }; -static int tun_flow_init(struct tun_struct *tun) +static void tun_flow_init(struct tun_struct *tun) { int i; @@ -850,10 +902,6 @@ static int tun_flow_init(struct tun_struct *tun) tun->ageing_time = TUN_FLOW_EXPIRE; setup_timer(&tun->flow_gc_timer, tun_flow_cleanup, (unsigned long)tun); - mod_timer(&tun->flow_gc_timer, - round_jiffies_up(jiffies + tun->ageing_time)); - - return 0; } static void tun_flow_uninit(struct tun_struct *tun) @@ -913,7 +961,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait) tun_debug(KERN_INFO, tun, "tun_chr_poll\n"); - poll_wait(file, &tfile->wq.wait, wait); + poll_wait(file, sk_sleep(sk), wait); if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; @@ -1076,6 +1124,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, int err; u32 rxhash; + if (!(tun->dev->flags & IFF_UP)) + return -EIO; + if (!(tun->flags & TUN_NO_PI)) { if (len < sizeof(pi)) return -EINVAL; @@ -1167,14 +1218,20 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } } + if (!(tun->flags & TUN_NO_PI)) + if (pi.flags & htons(CHECKSUM_UNNECESSARY)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: if (tun->flags & TUN_NO_PI) { - switch (skb->data[0] & 0xf0) { - case 0x40: + u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0; + + switch (ip_version) { + case 4: pi.proto = htons(ETH_P_IP); break; - case 0x60: + case 6: pi.proto = htons(ETH_P_IPV6); break; default: @@ -1193,6 +1250,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, break; } + skb_reset_network_header(skb); + if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { pr_debug("GSO!\n"); switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { @@ -1203,8 +1262,20 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; case VIRTIO_NET_HDR_GSO_UDP: + { + static bool warned; + + if (!warned) { + warned = true; + netdev_warn(tun->dev, + "%s: using disabled UFO feature; please fix this program\n", + current->comm); + } skb_shinfo(skb)->gso_type = SKB_GSO_UDP; + if (skb->protocol == htons(ETH_P_IPV6)) + ipv6_proxy_select_ident(skb); break; + } default: tun->dev->stats.rx_frame_errors++; kfree_skb(skb); @@ -1233,7 +1304,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; } - skb_reset_network_header(skb); skb_probe_transport_header(skb, 0); rxhash = skb_get_rxhash(skb); @@ -1274,8 +1344,13 @@ static ssize_t tun_put_user(struct tun_struct *tun, { struct tun_pi pi = { 0, skb->protocol }; ssize_t total = 0; + int vlan_offset = 0, copied; + int vlan_hlen = 0; int vnet_hdr_sz = 0; + if (vlan_tx_tag_present(skb)) + vlan_hlen = VLAN_HLEN; + if (tun->flags & TUN_VNET_HDR) vnet_hdr_sz = ACCESS_ONCE(tun->vnet_hdr_sz); @@ -1283,7 +1358,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, if ((len -= sizeof(pi)) < 0) return -EINVAL; - if (len < skb->len + vnet_hdr_sz) { + if (len < skb->len + vlan_hlen + vnet_hdr_sz) { /* Packet will be striped */ pi.flags |= TUN_PKT_STRIP; } @@ -1308,8 +1383,6 @@ static ssize_t tun_put_user(struct tun_struct *tun, gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (sinfo->gso_type & SKB_GSO_UDP) - gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; else { pr_err("unexpected GSO type: " "0x%x, gso_size %d, hdr_len %d\n", @@ -1329,7 +1402,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, if (skb->ip_summed == CHECKSUM_PARTIAL) { gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - gso.csum_start = skb_checksum_start_offset(skb); + gso.csum_start = skb_checksum_start_offset(skb) + + vlan_hlen; gso.csum_offset = skb->csum_offset; } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; @@ -1341,11 +1415,39 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += vnet_hdr_sz; } - len = min_t(int, skb->len, len); + copied = total; + len = min_t(int, skb->len + vlan_hlen, len); + total += skb->len + vlan_hlen; + if (vlan_hlen) { + int copy, ret; + struct { + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + } veth; + + veth.h_vlan_proto = skb->vlan_proto; + veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + + vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); + + copy = min_t(int, vlan_offset, len); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); + len -= copy; + copied += copy; + if (ret || !len) + goto done; - skb_copy_datagram_const_iovec(skb, 0, iv, total, len); - total += skb->len; + copy = min_t(int, sizeof(veth), len); + ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); + len -= copy; + copied += copy; + if (ret || !len) + goto done; + } + skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); + +done: tun->dev->stats.tx_packets++; tun->dev->stats.tx_bytes += len; @@ -1356,45 +1458,23 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, struct kiocb *iocb, const struct iovec *iv, ssize_t len, int noblock) { - DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t ret = 0; + int peeked, err, off = 0; tun_debug(KERN_INFO, tun, "tun_do_read\n"); - if (unlikely(!noblock)) - add_wait_queue(&tfile->wq.wait, &wait); - while (len) { - current->state = TASK_INTERRUPTIBLE; - - /* Read frames from the queue */ - if (!(skb = skb_dequeue(&tfile->socket.sk->sk_receive_queue))) { - if (noblock) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - if (tun->dev->reg_state != NETREG_REGISTERED) { - ret = -EIO; - break; - } - - /* Nothing to read, let's sleep */ - schedule(); - continue; - } + if (!len) + return ret; + /* Read frames from queue */ + skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, + &peeked, &off, &err); + if (skb) { ret = tun_put_user(tun, tfile, skb, iv, len); kfree_skb(skb); - break; - } - - current->state = TASK_RUNNING; - if (unlikely(!noblock)) - remove_wait_queue(&tfile->wq.wait, &wait); + } else + ret = err; return ret; } @@ -1496,7 +1576,6 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock, return ret; } - static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len, int flags) @@ -1508,13 +1587,18 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, if (!tun) return -EBADFD; - if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) { + if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) { ret = -EINVAL; goto out; } + if (flags & MSG_ERRQUEUE) { + ret = sock_recv_errqueue(sock->sk, m, total_len, + SOL_PACKET, TUN_TX_TIMESTAMP); + goto out; + } ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len, flags & MSG_DONTWAIT); - if (ret > total_len) { + if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; } @@ -1567,6 +1651,9 @@ static int tun_flags(struct tun_struct *tun) if (tun->flags & TUN_TAP_MQ) flags |= IFF_MULTI_QUEUE; + if (tun->flags & TUN_PERSIST) + flags |= IFF_PERSIST; + return flags; } @@ -1632,7 +1719,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (err < 0) return err; - err = tun_attach(tun, file); + err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER); if (err < 0) return err; @@ -1676,9 +1763,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (!dev) return -ENOMEM; + err = dev_get_valid_name(net, dev, name); + if (err < 0) + goto err_free_dev; dev_net_set(dev, net); dev->rtnl_link_ops = &tun_link_ops; + dev->ifindex = tfile->ifindex; tun = netdev_priv(dev); tun->dev = dev; @@ -1696,18 +1787,18 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_dev; tun_net_init(dev); - - err = tun_flow_init(tun); - if (err < 0) - goto err_free_dev; + tun_flow_init(tun); dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | - TUN_USER_FEATURES; - dev->features = dev->hw_features; - dev->vlan_features = dev->features; + TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX; + dev->features = dev->hw_features | NETIF_F_LLTX; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX); INIT_LIST_HEAD(&tun->disabled); - err = tun_attach(tun, file); + err = tun_attach(tun, file, false); if (err < 0) goto err_free_flow; @@ -1799,11 +1890,6 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) features |= NETIF_F_TSO6; arg &= ~(TUN_F_TSO4|TUN_F_TSO6); } - - if (arg & TUN_F_UFO) { - features |= NETIF_F_UFO; - arg &= ~TUN_F_UFO; - } } /* This gives the user a way to test for new features in future by @@ -1812,6 +1898,8 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) return -EINVAL; tun->set_features = features; + tun->dev->wanted_features &= ~TUN_USER_FEATURES; + tun->dev->wanted_features |= features; netdev_update_features(tun->dev); return 0; @@ -1876,7 +1964,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) ret = security_tun_dev_attach_queue(tun->security); if (ret < 0) goto unlock; - ret = tun_attach(tun, file); + ret = tun_attach(tun, file, false); } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { tun = rtnl_dereference(tfile->tun); if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached) @@ -1902,6 +1990,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, kgid_t group; int sndbuf; int vnet_hdr_sz; + unsigned int ifindex; int ret; #ifdef CONFIG_ANDROID_PARANOID_NETWORK @@ -1910,7 +1999,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, } #endif - if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) { + if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == SOCK_IOC_TYPE) { if (copy_from_user(&ifr, argp, ifreq_len)) return -EFAULT; } else { @@ -1930,7 +2019,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, rtnl_lock(); tun = __tun_get(tfile); - if (cmd == TUNSETIFF && !tun) { + if (cmd == TUNSETIFF) { + ret = -EEXIST; + if (tun) + goto unlock; + ifr.ifr_name[IFNAMSIZ-1] = '\0'; ret = tun_set_iff(tfile->net, file, &ifr); @@ -1942,6 +2035,19 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, ret = -EFAULT; goto unlock; } + if (cmd == TUNSETIFINDEX) { + ret = -EPERM; + if (tun) + goto unlock; + + ret = -EFAULT; + if (copy_from_user(&ifindex, argp, sizeof(ifindex))) + goto unlock; + + ret = 0; + tfile->ifindex = ifindex; + goto unlock; + } ret = -EBADFD; if (!tun) @@ -1954,6 +2060,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, case TUNGETIFF: tun_get_iff(current->nsproxy->net_ns, tun, &ifr); + if (tfile->detached) + ifr.ifr_flags |= IFF_DETACH_QUEUE; + if (!tfile->socket.sk->sk_filter) + ifr.ifr_flags |= IFF_NOFILTER; + if (copy_to_user(argp, &ifr, ifreq_len)) ret = -EFAULT; break; @@ -2065,6 +2176,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, ret = -EFAULT; break; } + if (sndbuf <= 0) { + ret = -EINVAL; + break; + } tun->sndbuf = sndbuf; tun_set_sndbuf(tun); @@ -2110,6 +2225,16 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, tun_detach_filter(tun, tun->numqueues); break; + case TUNGETFILTER: + ret = -EINVAL; + if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) + break; + ret = -EFAULT; + if (copy_to_user(argp, &tun->fprog, sizeof(tun->fprog))) + break; + ret = 0; + break; + default: ret = -EINVAL; break; @@ -2187,12 +2312,13 @@ static int tun_chr_open(struct inode *inode, struct file * file) &tun_proto); if (!tfile) return -ENOMEM; - rcu_assign_pointer(tfile->tun, NULL); + RCU_INIT_POINTER(tfile->tun, NULL); tfile->net = get_net(current->nsproxy->net_ns); tfile->flags = 0; + tfile->ifindex = 0; - rcu_assign_pointer(tfile->socket.wq, &tfile->wq); init_waitqueue_head(&tfile->wq.wait); + RCU_INIT_POINTER(tfile->socket.wq, &tfile->wq); tfile->socket.file = file; tfile->socket.ops = &tun_socket_ops; @@ -2223,6 +2349,27 @@ static int tun_chr_close(struct inode *inode, struct file *file) return 0; } +#ifdef CONFIG_PROC_FS +static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct tun_struct *tun; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + + rtnl_lock(); + tun = tun_get(f); + if (tun) + tun_get_iff(current->nsproxy->net_ns, tun, &ifr); + rtnl_unlock(); + + if (tun) + tun_put(tun); + + return seq_printf(m, "iff:\t%s\n", ifr.ifr_name); +} +#endif + static const struct file_operations tun_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -2237,7 +2384,10 @@ static const struct file_operations tun_fops = { #endif .open = tun_chr_open, .release = tun_chr_close, - .fasync = tun_chr_fasync + .fasync = tun_chr_fasync, +#ifdef CONFIG_PROC_FS + .show_fdinfo = tun_chr_show_fdinfo, +#endif }; static struct miscdevice tun_miscdev = { @@ -2305,6 +2455,7 @@ static const struct ethtool_ops tun_ethtool_ops = { .get_msglevel = tun_get_msglevel, .set_msglevel = tun_set_msglevel, .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, }; @@ -2313,7 +2464,6 @@ static int __init tun_init(void) int ret = 0; pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); - pr_info("%s\n", DRV_COPYRIGHT); ret = rtnl_link_register(&tun_link_ops); if (ret) { diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 88c08df5a976d34a41bf9f7f21322b6284d24ee0..11300560d751c92dfb948baf0ef40ac53a3670f8 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -771,6 +771,9 @@ static int ax88178_change_mtu(struct net_device *net, int new_mtu) dev->hard_mtu = net->mtu + net->hard_header_len; ax88178_set_mfb(dev); + /* max qlen depend on hard_mtu and rx_urb_size */ + usbnet_update_max_qlen(dev); + return 0; } diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 841841b47396bae700198ecefe7bf10cd785a6f3..3b1fe210d21603de489dfc740bd16578a2e03fd5 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -688,6 +688,9 @@ static int ax88179_change_mtu(struct net_device *net, int new_mtu) 2, 2, &tmp16); } + /* max qlen depend on hard_mtu and rx_urb_size */ + usbnet_update_max_qlen(dev); + return 0; } diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 7d78669000d704d8448aea5e24a8a73c312badfc..8c252cf51f433d06ccb4a89331c70f32c3f0b5ee 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -328,7 +328,7 @@ MODULE_DEVICE_TABLE(usb, usbpn_ids); static struct usb_driver usbpn_driver; -int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) { static const char ifname[] = "usbpn%d"; const struct usb_cdc_union_desc *union_header = NULL; @@ -343,9 +343,9 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) data = intf->altsetting->extra; len = intf->altsetting->extralen; - while (len >= 3) { + while (len > 0) { u8 dlen = data[0]; - if (dlen < 3) + if ((len < dlen) || (dlen < 3 )) return -EINVAL; /* bDescriptorType */ diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index ea0a686a09ebd19fd8fd201dfe15f9a7a822aeec..3097ee83ac9729f922bc22c78ef2aa4e416da617 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -128,7 +128,13 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) memset(info, 0, sizeof *info); info->control = intf; - while (len > 3) { + while (len > 0) { + + if ((len < buf [0]) || (buf [0] < 3)) { + dev_dbg(&intf->dev, "invalid descriptor buffer length\n"); + goto bad_desc; + } + if (buf [1] != USB_DT_CS_INTERFACE) goto next_desc; @@ -145,6 +151,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC header\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_header_desc)) + break; info->header = (void *) buf; if (info->header->bLength != sizeof *info->header) { dev_dbg(&intf->dev, "CDC header len %u\n", @@ -158,6 +166,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) */ if (rndis) { struct usb_cdc_acm_descriptor *acm; + if (len < sizeof(struct usb_cdc_acm_descriptor)) + break; acm = (void *) buf; if (acm->bmCapabilities) { @@ -174,6 +184,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC union\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_union_desc)) + break; info->u = (void *) buf; if (info->u->bLength != sizeof *info->u) { dev_dbg(&intf->dev, "CDC union len %u\n", @@ -228,6 +240,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra CDC ether\n"); goto bad_desc; } + if (len < sizeof(struct usb_cdc_ether_desc)) + break; info->ether = (void *) buf; if (info->ether->bLength != sizeof *info->ether) { dev_dbg(&intf->dev, "CDC ether len %u\n", @@ -245,7 +259,6 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) dev_dbg(&intf->dev, "extra MDLM descriptor\n"); goto bad_desc; } - desc = (void *)buf; if (desc->bLength != sizeof(*desc)) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 7ac104b39c772caa6d04f24df376983020b545e3..6b22884d352017a422e95d908619e2b7cf3a8f7f 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -271,6 +271,7 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* if value changed, update device */ if (ctx->max_datagram_size != le16_to_cpu(max_datagram_size)) { + max_datagram_size = cpu_to_le16(ctx->max_datagram_size); err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_OUT @@ -610,9 +611,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) return -ENODEV; - /* NCM data altsetting is always 1 */ - return cdc_ncm_bind_common(dev, intf, 1); - + return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); } static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max) @@ -1159,7 +1158,7 @@ static void cdc_ncm_disconnect(struct usb_interface *intf) static const struct driver_info cdc_ncm_info = { .description = "CDC NCM", .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET - | FLAG_LINK_INTR, + | FLAG_LINK_INTR, .bind = cdc_ncm_bind, .unbind = cdc_ncm_unbind, .check_connect = cdc_ncm_check_connect, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 12aaf1f4f8902a8ad42f9e2fcf06c847d703b80f..a713cffac07bf2b4fc95ddb0e86140828e500d4c 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -235,9 +235,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) info->data = intf; /* and a number of CDC descriptors */ - while (len > 3) { + while (len > 0) { struct usb_descriptor_header *h = (void *)buf; + if ((len < buf[0]) || (buf[0] < 3)) { + dev_dbg(&intf->dev, "invalid descriptor buffer length\n"); + goto err; + } + /* ignore any misplaced descriptors */ if (h->bDescriptorType != USB_DT_CS_INTERFACE) goto next_desc; @@ -823,6 +828,7 @@ MODULE_DEVICE_TABLE(usb, products); static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device_id *id = (struct usb_device_id *)prod; + struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; /* Workaround to enable dynamic IDs. This disables usbnet * blacklisting functionality. Which, if required, can be @@ -834,6 +840,18 @@ static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id id->driver_info = (unsigned long)&qmi_wwan_info; } + /* There are devices where the same interface number can be + * configured as different functions. We should only bind to + * vendor specific functions when matching on interface number + */ + if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER && + desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) { + dev_dbg(&intf->dev, + "Rejecting interface number match for class %02x\n", + desc->bInterfaceClass); + return -ENODEV; + } + return usbnet_probe(intf, id); } diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c index 75e97832efa22075d4bec479b079ac82a895d7d8..25ebe1361efdfdf9d806ffc0e4b5eb01380cff03 100644 --- a/drivers/net/usb/rmnet_usb_ctrl.c +++ b/drivers/net/usb/rmnet_usb_ctrl.c @@ -1219,12 +1219,13 @@ skip_cudev_init: "%s%d", rmnet_dev_names[i], n); if (IS_ERR(dev->devicep)) { + long status = PTR_ERR(dev->devicep); pr_err("%s: device_create() returned %ld\n", - __func__, PTR_ERR(dev->devicep)); + __func__, status); cdev_del(&dev->cdev); free_rmnet_ctrl_udev(dev->cudev); kfree(dev); - return PTR_ERR(dev->devicep); + return status; } /*create /sys/class/hsicctl/hsicctlx/modem_wait*/ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1c8a373273e58969d83d7343cec2747a5e0b2cb6..e8f10461ca6fcf95233b111dbe2fac2e98e252bf 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -59,15 +59,13 @@ * For high speed, each frame comfortably fits almost 36 max size * Ethernet packets (so queues should be bigger). * - * REVISIT qlens should be members of 'struct usbnet'; the goal is to - * let the USB host controller be busy for 5msec or more before an irq - * is required, under load. Jumbograms change the equation. + * The goal is to let the USB host controller be busy for 5msec or + * more before an irq is required, under load. Jumbograms change + * the equation. */ -#define RX_MAX_QUEUE_MEMORY (60 * 1518) -#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ - (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4) -#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ - (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4) +#define MAX_QUEUE_MEMORY (60 * 1518) +#define RX_QLEN(dev) ((dev)->rx_qlen) +#define TX_QLEN(dev) ((dev)->tx_qlen) // reawaken network queue this soon after stopping; else watchdog barks #define TX_TIMEOUT_JIFFIES (5*HZ) @@ -350,6 +348,31 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(usbnet_skb_return); +/* must be called if hard_mtu or rx_urb_size changed */ +void usbnet_update_max_qlen(struct usbnet *dev) +{ + enum usb_device_speed speed = dev->udev->speed; + + switch (speed) { + case USB_SPEED_HIGH: + dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size; + dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu; + break; + case USB_SPEED_SUPER: + /* + * Not take default 5ms qlen for super speed HC to + * save memory, and iperf tests show 2.5ms qlen can + * work well + */ + dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size; + dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu; + break; + default: + dev->rx_qlen = dev->tx_qlen = 4; + } +} +EXPORT_SYMBOL_GPL(usbnet_update_max_qlen); + /*------------------------------------------------------------------------- * @@ -378,6 +401,9 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu) usbnet_unlink_rx_urbs(dev); } + /* max qlen depend on hard_mtu and rx_urb_size */ + usbnet_update_max_qlen(dev); + return 0; } EXPORT_SYMBOL_GPL(usbnet_change_mtu); @@ -847,6 +873,9 @@ int usbnet_open (struct net_device *net) goto done; } + /* hard_mtu or rx_urb_size may change in reset() */ + usbnet_update_max_qlen(dev); + // insist peer be connected if (info->check_connect && (retval = info->check_connect (dev)) < 0) { netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval); @@ -931,6 +960,9 @@ int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) if (dev->driver_info->link_reset) dev->driver_info->link_reset(dev); + /* hard_mtu or rx_urb_size may change in link_reset() */ + usbnet_update_max_qlen(dev); + return retval; } @@ -1024,16 +1056,34 @@ static void __handle_link_change(struct usbnet *dev) queue_work(usbnet_wq, &dev->bh_w); } + /* hard_mtu or rx_urb_size may change during link change */ + usbnet_update_max_qlen(dev); + clear_bit(EVENT_LINK_CHANGE, &dev->flags); } +static void usbnet_set_rx_mode(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + usbnet_defer_kevent(dev, EVENT_SET_RX_MODE); +} + +static void __handle_set_rx_mode(struct usbnet *dev) +{ + if (dev->driver_info->set_rx_mode) + (dev->driver_info->set_rx_mode)(dev); + + clear_bit(EVENT_SET_RX_MODE, &dev->flags); +} + /* work that cannot be done in interrupt context uses keventd. * * NOTE: with 2.5 we could do more of this using completion callbacks, * especially now that control transfers can be queued. */ static void -kevent (struct work_struct *work) +usbnet_deferred_kevent (struct work_struct *work) { struct usbnet *dev = container_of(work, struct usbnet, kevent); @@ -1132,6 +1182,10 @@ skip_reset: if (test_bit (EVENT_LINK_CHANGE, &dev->flags)) __handle_link_change(dev); + if (test_bit (EVENT_SET_RX_MODE, &dev->flags)) + __handle_set_rx_mode(dev); + + if (dev->flags) netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); } @@ -1201,6 +1255,39 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout); /*-------------------------------------------------------------------------*/ +static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) +{ + unsigned num_sgs, total_len = 0; + int i, s = 0; + + num_sgs = skb_shinfo(skb)->nr_frags + 1; + if (num_sgs == 1) + return 0; + + /* reserve one for zero packet */ + urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist), + GFP_ATOMIC); + if (!urb->sg) + return -ENOMEM; + + urb->num_sgs = num_sgs; + sg_init_table(urb->sg, urb->num_sgs + 1); + + sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); + total_len += skb_headlen(skb); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i]; + + total_len += skb_frag_size(f); + sg_set_page(&urb->sg[i + s], f->page.p, f->size, + f->page_offset); + } + urb->transfer_buffer_length = total_len; + + return 1; +} + netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) { @@ -1227,7 +1314,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, goto drop; } } - length = skb->len; if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { netif_dbg(dev, tx_err, dev->net, "no urb\n"); @@ -1237,10 +1323,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->length = length; usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); + if (dev->can_dma_sg) { + if (build_dma_sg(skb, urb) < 0) + goto drop; + } + length = urb->transfer_buffer_length; /* don't assume the hardware handles USB_ZERO_PACKET * NOTE: strictly conforming cdc-ether devices should expect @@ -1252,15 +1342,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, if (length % dev->maxpacket == 0) { if (!(info->flags & FLAG_SEND_ZLP)) { if (!(info->flags & FLAG_MULTI_PACKET)) { - urb->transfer_buffer_length++; - if (skb_tailroom(skb)) { + length++; + if (skb_tailroom(skb) && !urb->num_sgs) { skb->data[skb->len] = 0; __skb_put(skb, 1); - } + } else if (urb->num_sgs) + sg_set_buf(&urb->sg[urb->num_sgs++], + dev->padding_pkt, 1); } } else urb->transfer_flags |= URB_ZERO_PACKET; } + entry->length = urb->transfer_buffer_length = length; spin_lock_irqsave(&dev->txq.lock, flags); retval = usb_autopm_get_interface_async(dev->intf); @@ -1309,7 +1402,10 @@ drop: not_drop: if (skb) dev_kfree_skb_any (skb); - usb_free_urb (urb); + if (urb) { + kfree(urb->sg); + usb_free_urb(urb); + } } else netif_dbg(dev, tx_queued, dev->net, "> tx, len %d, type 0x%x\n", length, skb->protocol); @@ -1361,6 +1457,7 @@ static void usbnet_bh (unsigned long param) rx_process (dev, skb); continue; case tx_done: + kfree(entry->urb->sg); case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); @@ -1451,6 +1548,7 @@ void usbnet_disconnect (struct usb_interface *intf) usb_kill_urb(dev->interrupt); usb_free_urb(dev->interrupt); + kfree(dev->padding_pkt); free_netdev(net); } @@ -1461,6 +1559,7 @@ static const struct net_device_ops usbnet_netdev_ops = { .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_set_rx_mode = usbnet_set_rx_mode, .ndo_change_mtu = usbnet_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -1525,19 +1624,19 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK); - init_waitqueue_head(&dev->wait); + init_waitqueue_head (&dev->wait); skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); - skb_queue_head_init(&dev->rxq_pause); - INIT_WORK(&dev->bh_w, usbnet_bh_w); - INIT_WORK (&dev->kevent, kevent); + skb_queue_head_init (&dev->rxq_pause); + INIT_WORK (&dev->bh_w, usbnet_bh_w); + INIT_WORK (&dev->kevent, usbnet_deferred_kevent); init_usb_anchor(&dev->deferred); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); mutex_init (&dev->phy_mutex); - mutex_init(&dev->interrupt_mutex); + mutex_init (&dev->interrupt_mutex); dev->interrupt_count = 0; dev->net = net; @@ -1609,14 +1708,30 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); + /* let userspace know we have a random address */ + if (ether_addr_equal(net->dev_addr, node_id)) + net->addr_assign_type = NET_ADDR_RANDOM; + if ((dev->driver_info->flags & FLAG_WLAN) != 0) SET_NETDEV_DEVTYPE(net, &wlan_type); if ((dev->driver_info->flags & FLAG_WWAN) != 0) SET_NETDEV_DEVTYPE(net, &wwan_type); + /* initialize max rx_qlen and tx_qlen */ + usbnet_update_max_qlen(dev); + + if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) && + !(info->flags & FLAG_MULTI_PACKET)) { + dev->padding_pkt = kzalloc(1, GFP_KERNEL); + if (!dev->padding_pkt) { + status = -ENOMEM; + goto out4; + } + } + status = register_netdev (net); if (status) - goto out4; + goto out5; netif_info(dev, probe, dev->net, "register '%s' at usb-%s-%s, %s, %pM\n", udev->dev.driver->name, @@ -1634,6 +1749,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) return 0; +out5: + kfree(dev->padding_pkt); out4: usb_free_urb(dev->interrupt); out3: @@ -1711,6 +1828,7 @@ int usbnet_resume (struct usb_interface *intf) retval = usb_submit_urb(res, GFP_ATOMIC); if (retval < 0) { dev_kfree_skb_any(skb); + kfree(res->sg); usb_free_urb(res); usb_autopm_put_interface_async(dev->intf); } else { diff --git a/drivers/net/veth.c b/drivers/net/veth.c index cc6d3f98743693d85b0a50565782e2d8bdcb275e..ce9d113303f7f0fd4a7e3b9a39c47c76c7e04741 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -346,6 +346,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (ifmp && (dev->ifindex != 0)) peer->ifindex = ifmp->ifi_index; + peer->gso_max_size = dev->gso_max_size; + peer->gso_max_segs = dev->gso_max_segs; + err = register_netdevice(peer); put_net(net); net = NULL; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b5d11529a39b01024a2e83c2026f5139228a729c..830d5f275952e8d062d737dd7738390e62f1c196 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -435,8 +435,17 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len) skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; break; case VIRTIO_NET_HDR_GSO_UDP: + { + static bool warned; + + if (!warned) { + warned = true; + netdev_warn(dev, + "host using disabled UFO feature; please fix it\n"); + } skb_shinfo(skb)->gso_type = SKB_GSO_UDP; break; + } case VIRTIO_NET_HDR_GSO_TCPV6: skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; @@ -735,8 +744,6 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) - hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) @@ -1550,7 +1557,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { - dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO + dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } /* Individual feature bits: what can host handle? */ @@ -1560,11 +1567,9 @@ static int virtnet_probe(struct virtio_device *vdev) dev->hw_features |= NETIF_F_TSO6; if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) dev->hw_features |= NETIF_F_TSO_ECN; - if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->hw_features |= NETIF_F_UFO; if (gso) - dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); + dev->features |= dev->hw_features & NETIF_F_ALL_TSO; /* (!csum && gso) case will be fixed by register_netdev() */ } @@ -1597,8 +1602,7 @@ static int virtnet_probe(struct virtio_device *vdev) /* If we can receive ANY GSO packets, we must allocate large ones. */ if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO)) + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) vi->big_packets = true; if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) @@ -1781,9 +1785,9 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, - VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, - VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, + VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 8912ba83fd77f9e7d067f55e8cd7bb282d0ee336..a49051d718c7eb8f0b2310239494783635e7da9c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -579,7 +579,7 @@ static bool vxlan_snoop(struct net_device *dev, return false; /* Don't migrate static entries, drop packets */ - if (f->state & NUD_NOARP) + if (f->state & (NUD_PERMANENT | NUD_NOARP)) return true; if (net_ratelimit()) diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index d43f4efd3e07abc6d62fff0343cfd46cec609097..f041d180feb3866ed70ec116566aef4bb13dfd94 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -57,6 +57,7 @@ #include #include +#include #include #include @@ -176,7 +177,7 @@ static u32 mac[ SBNI_MAX_NUM_CARDS ] __initdata; #ifndef MODULE typedef u32 iarr[]; -static iarr __initdata *dest[5] = { &io, &irq, &baud, &rxl, &mac }; +static iarr *dest[5] __initdata = { &io, &irq, &baud, &rxl, &mac }; #endif /* A zero-terminated list of I/O addresses to be probed on ISA bus */ @@ -1360,6 +1361,8 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) if( !slave_dev || !(slave_dev->flags & IFF_UP) ) { netdev_err(dev, "trying to enslave non-active device %s\n", slave_name); + if (slave_dev) + dev_put(slave_dev); return -EPERM; } diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 470cdb9817ed6bc052679d9b3399efaf7d143e43..c635b9e48882fbca24d582d3b9768228d9258db2 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -295,6 +295,7 @@ config WCNSS_CORE select WEXT_PRIV select WEXT_CORE select WEXT_SPY + select CNSS_CRYPTO ---help--- Core driver for the Qualcomm WCNSS triple play connectivity subsystem @@ -319,6 +320,14 @@ config WCNSS_REGISTER_DUMP_ON_BITE register access failures. So this feature is to enable/disable the register dump on WCNSS WDOG bite. +config CNSS_CRYPTO + tristate "Enable CNSS crypto support" + ---help--- + Add crypto support for the WLAN driver module. + This feature enable wlan driver to use the crypto APIs exported + from cnss platform driver. This crypto APIs used to generate cipher + key and add support for the WLAN driver module security protocol. + config BCMDHD_PCIE bool "PCIe bus interface support" depends on PCI @@ -356,9 +365,9 @@ config SOMC_WIFI_CONTROL source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" -source "drivers/net/wireless/bcmdhd/Kconfig" -source "drivers/net/wireless/bcmdhd_suzuran/Kconfig" source "drivers/net/wireless/brcm80211/Kconfig" +source "drivers/net/wireless/bcmdhd_bcm43455/Kconfig" +source "drivers/net/wireless/bcmdhd_bcm4356/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 93a6aa23cfcfe657b5d5162029ce09ab82f3ff47..3890ef3526dbd09e9b60830c1eb7c170c38b5fb1 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -57,13 +57,14 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ obj-$(CONFIG_SOMC_WIFI_CONTROL) += somcwifictrl/ -obj-$(CONFIG_BCMDHD) += bcmdhd/ -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd_suzuran/ +obj-$(CONFIG_BCMDHD_BCM43455) += bcmdhd_bcm43455/ +obj-$(CONFIG_BCMDHD_BCM4356) += bcmdhd_bcm4356/ + obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/ obj-$(CONFIG_LIBRA_SDIOIF) += libra/ obj-$(CONFIG_WCNSS_CORE) += wcnss/ -obj-$(CONFIG_CNSS_SDIO) += cnss/cnss_sdio.o obj-$(CONFIG_CNSS) += cnss/ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ +obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 008b4d92b29a4772b8437632e036160724d021d5..be6d096ff9452ef1fedb56415f25555085109101 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2977,11 +2977,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac) + struct station_del_parameters *params) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); - const u8 *addr = mac ? mac : bcast_addr; + const u8 *addr = params->mac ? params->mac : bcast_addr; return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 152cecef0378a056fce83825436685fcfbb0bafd..739a262e3ebffbd090f69e8822d39287239c921b 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -334,6 +334,30 @@ out: return rc; } +static void wil_print_crypto(struct wil6210_priv *wil, + struct cfg80211_crypto_settings *c) +{ + int i, n; + + wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", + c->wpa_versions, c->cipher_group); + wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise); + n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->ciphers_pairwise[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites); + n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->akm_suites[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", + c->control_port, be16_to_cpu(c->control_port_ethertype), + c->control_port_no_encrypt); +} + static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { @@ -348,6 +372,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil, print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); + wil_print_crypto(wil, &sme->crypto); } static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -362,11 +387,25 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; + wil_print_connect_params(wil, sme); + if (test_bit(wil_status_fwconnecting, wil->status) || test_bit(wil_status_fwconnected, wil->status)) return -EALREADY; - wil_print_connect_params(wil, sme); + if (sme->ie_len > WMI_MAX_IE_LEN) { + wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len); + return -ERANGE; + } + + rsn_eid = sme->ie ? + cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : + NULL; + + if (sme->privacy && !rsn_eid) { + wil_err(wil, "Missing RSN IE for secure connection\n"); + return -EINVAL; + } bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, @@ -382,17 +421,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = -ENOENT; goto out; } + wil->privacy = sme->privacy; - rsn_eid = sme->ie ? - cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : - NULL; - if (rsn_eid) { - if (sme->ie_len > WMI_MAX_IE_LEN) { - rc = -ERANGE; - wil_err(wil, "IE too large (%td bytes)\n", - sme->ie_len); - goto out; - } + if (wil->privacy) { /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */ rc = wmi_del_cipher_key(wil, 0, bss->bssid); if (rc) { @@ -425,7 +456,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, bss->capability); goto out; } - if (rsn_eid) { + if (wil->privacy) { conn.dot11_auth_mode = WMI_AUTH11_SHARED; conn.auth_mode = WMI_AUTH_WPA2_PSK; conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; @@ -454,6 +485,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { + netif_carrier_on(ndev); /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); @@ -485,6 +517,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { + size_t total; struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; bool tx_status = false; @@ -495,7 +528,14 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct wmi_sw_tx_complete_event evt; } __packed evt; - cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); + if (len < sizeof(struct ieee80211_mgmt)) + return -EINVAL; + + total = sizeof(*cmd) + len; + if (total < len) + return -EINVAL; + + cmd = kmalloc(total, GFP_KERNEL); if (!cmd) { rc = -ENOMEM; goto out; @@ -505,7 +545,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, cmd->len = cpu_to_le16(len); memcpy(cmd->payload, buf, len); - rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (rc == 0) tx_status = !evt.evt.status; @@ -618,18 +658,6 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) b->assocresp_ies, b->assocresp_ies_len); } -static void wil_print_crypto(struct wil6210_priv *wil, - struct cfg80211_crypto_settings *c) -{ - wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", - c->wpa_versions, c->cipher_group); - wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise); - wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites); - wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", - c->control_port, be16_to_cpu(c->control_port_ethertype), - c->control_port_no_encrypt); -} - static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { @@ -755,14 +783,14 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); - wil->secure_pcp = info->privacy; + wil->privacy = info->privacy; + + netif_carrier_on(ndev); rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - goto out; - - netif_carrier_on(ndev); + netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); @@ -772,37 +800,132 @@ out: static int wil_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - int rc, rc1; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s()\n", __func__); + netif_carrier_off(ndev); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); - rc = wmi_pcp_stop(wil); + wmi_pcp_stop(wil); __wil_down(wil); - rc1 = __wil_up(wil); + __wil_up(wil); mutex_unlock(&wil->mutex); - return min(rc, rc1); + /* some functions above might fail (e.g. __wil_up). Nevertheless, we + * return success because AP has stopped + */ + return 0; } static int wil_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac) + struct net_device *dev, + struct station_del_parameters *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); - wil6210_disconnect(wil, mac, WLAN_REASON_UNSPECIFIED, false); + wil6210_disconnect(wil, (u8 *)params->mac, WLAN_REASON_UNSPECIFIED, + false); mutex_unlock(&wil->mutex); return 0; } +/* probe_client handling */ +static void wil_probe_client_handle(struct wil6210_priv *wil, + struct wil_probe_client_req *req) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct wil_sta_info *sta = &wil->sta[req->cid]; + /* assume STA is alive if it is still connected, + * else FW will disconnect it + */ + bool alive = (sta->status == wil_sta_connected); + + cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL); +} + +static struct list_head *next_probe_client(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->probe_client_mutex); + + if (!list_empty(&wil->probe_client_pending)) { + ret = wil->probe_client_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->probe_client_mutex); + + return ret; +} + +void wil_probe_client_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + probe_client_worker); + struct wil_probe_client_req *req; + struct list_head *lh; + + while ((lh = next_probe_client(wil)) != NULL) { + req = list_entry(lh, struct wil_probe_client_req, list); + + wil_probe_client_handle(wil, req); + kfree(req); + } +} + +void wil_probe_client_flush(struct wil6210_priv *wil) +{ + struct wil_probe_client_req *req, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->probe_client_mutex); + + list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) { + list_del(&req->list); + kfree(req); + } + + mutex_unlock(&wil->probe_client_mutex); +} + +static int wil_cfg80211_probe_client(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil_probe_client_req *req; + int cid = wil_find_cid(wil, peer); + + wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid); + + if (cid < 0) + return -ENOLINK; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->cid = cid; + req->cookie = cid; + + mutex_lock(&wil->probe_client_mutex); + list_add_tail(&req->list, &wil->probe_client_pending); + mutex_unlock(&wil->probe_client_mutex); + + *cookie = req->cookie; + queue_work(wil->wq_service, &wil->probe_client_worker); + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, @@ -822,6 +945,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, + .probe_client = wil_cfg80211_probe_client, }; static void wil_wiphy_init(struct wiphy *wiphy) @@ -853,6 +977,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 148ae034922240092718d07553e3cdc49689fa88..bc755c4b59d6fa7861f4ff3896fcf2a33c5970ce 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -29,6 +29,7 @@ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ +u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */ enum dbg_off_type { doff_u32 = 0, @@ -102,23 +103,30 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) % vring->size; int avail = vring->size - used - 1; char name[10]; + char sidle[10]; /* performance monitoring */ cycles_t now = get_cycles(); uint64_t idle = txdata->idle * 100; uint64_t total = now - txdata->begin; - do_div(idle, total); + if (total != 0) { + do_div(idle, total); + snprintf(sidle, sizeof(sidle), "%3d%%", + (int)idle); + } else { + snprintf(sidle, sizeof(sidle), "N/A"); + } txdata->begin = now; txdata->idle = 0ULL; snprintf(name, sizeof(name), "tx_%2d", i); seq_printf(s, - "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n", - wil->sta[cid].addr, cid, tid, - txdata->agg_wsize, txdata->agg_timeout, - txdata->agg_amsdu ? "+" : "-", - used, avail, (int)idle); + "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", + wil->sta[cid].addr, cid, tid, + txdata->agg_wsize, txdata->agg_timeout, + txdata->agg_amsdu ? "+" : "-", + used, avail, sidle); wil_print_vring(s, wil, name, vring, '_', 'H'); } @@ -549,7 +557,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); - wil_reset(wil); + wil_reset(wil, true); return len; } @@ -697,8 +705,12 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, struct wiphy *wiphy = wil_to_wiphy(wil); struct wireless_dev *wdev = wil_to_wdev(wil); int rc; - void *frame = kmalloc(len, GFP_KERNEL); + void *frame; + + if (!len) + return -EINVAL; + frame = kmalloc(len, GFP_KERNEL); if (!frame) return -ENOMEM; @@ -1388,7 +1400,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, /* fields in struct wil6210_priv */ static const struct dbg_off dbg_wil_off[] = { - WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32), + WIL_FIELD(privacy, S_IRUGO, doff_u32), WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), @@ -1408,6 +1420,8 @@ static const struct dbg_off dbg_statics[] = { {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32}, {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32}, {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32}, + {"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh, + doff_u32}, {}, }; diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 4c44a82c34d79577e6e454bd42bbb9b8697d828e..0ea695ff98adeda1185382bfda7b58958b579275 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -50,27 +50,19 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, wil_dbg_misc(wil, "%s()\n", __func__); - if (test_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities)) { - tx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); - if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) - tx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); - - rx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); - if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) - rx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); - } else { - rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); - if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN) - rx_itr_val = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - } + tx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) + tx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); + + rx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) + rx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); cp->tx_coalesce_usecs = tx_itr_val; cp->rx_coalesce_usecs = rx_itr_val; diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 93c5cc16c515c8df5bfc3e2be9dea61e3249ee5a..4428345e5a470360560ceb82772349cf8f754a7f 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include "fw.h" MODULE_FIRMWARE(WIL_FW_NAME); +MODULE_FIRMWARE(WIL_FW2_NAME); /* target operations */ /* register read */ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index d4acf93a9a02b9fbfd9f5d063726bdd5e84d47c5..69109f0d47640b11fb3b9af3719b3a2bff6efd8c 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,14 +26,17 @@ prefix_type, rowsize, \ groupsize, buf, len, ascii) -#define FW_ADDR_CHECK(ioaddr, val, msg) do { \ - ioaddr = wmi_buffer(wil, val); \ - if (!ioaddr) { \ - wil_err_fw(wil, "bad " msg ": 0x%08x\n", \ - le32_to_cpu(val)); \ - return -EINVAL; \ - } \ - } while (0) +static bool wil_fw_addr_check(struct wil6210_priv *wil, + void __iomem **ioaddr, __le32 val, + u32 size, const char *msg) +{ + *ioaddr = wmi_buffer_block(wil, val, size); + if (!(*ioaddr)) { + wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val)); + return false; + } + return true; +} /** * wil_fw_verify - verify firmware file validity @@ -138,7 +141,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data, return -EINVAL; } - FW_ADDR_CHECK(dst, d->addr, "address"); + if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) + return -EINVAL; wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr), s); wil_memcpy_toio_32(dst, d->data, s); @@ -170,7 +174,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data, return -EINVAL; } - FW_ADDR_CHECK(dst, d->addr, "address"); + if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) + return -EINVAL; v = le32_to_cpu(d->value); wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n", @@ -219,7 +224,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, u32 v = le32_to_cpu(block[i].value); u32 x, y; - FW_ADDR_CHECK(dst, block[i].addr, "address"); + if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address")) + return -EINVAL; x = ioread32(dst); y = (x & m) | (v & ~m); @@ -285,10 +291,15 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n", n, gw_cmd); - FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); - FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr"); - FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); - FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); + if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, + "gateway_addr_addr") || + !wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0, + "gateway_value_addr") || + !wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0, + "gateway_cmd_addr") || + !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0, + "gateway_ctrl_address")) + return -EINVAL; wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x" " cmd 0x%08x ctl 0x%08x\n", @@ -344,12 +355,19 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n", n, gw_cmd); - FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); + if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, + "gateway_addr_addr")) + return -EINVAL; for (k = 0; k < ARRAY_SIZE(block->value); k++) - FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k], - "gateway_value_addr"); - FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); - FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); + if (!wil_fw_addr_check(wil, &gwa_val[k], + d->gateway_value_addr[k], + 0, "gateway_value_addr")) + return -EINVAL; + if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0, + "gateway_cmd_addr") || + !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0, + "gateway_ctrl_address")) + return -EINVAL; wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n", le32_to_cpu(d->gateway_addr_addr), @@ -451,8 +469,6 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size) } return -EINVAL; } - /* Mark FW as loaded from host */ - S(RGF_USER_USAGE_6, 1); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index a6f923086f310d5795ef5beb4c3ebf61315001e9..1b096c5464c28727dad1d7f11746f20ea5d3e79d 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -166,9 +166,16 @@ void wil_unmask_irq(struct wil6210_priv *wil) /* target write operation */ #define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -static -void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) +void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { + wil_dbg_irq(wil, "%s()\n", __func__); + + /* disable interrupt moderation for monitor + * to get better timestamp precision + */ + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) + return; + /* Disable and clear tx counter before (re)configuration */ W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); @@ -206,42 +213,8 @@ void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); } -static -void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil) -{ - /* disable, use usec resolution */ - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR); - - wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration); - W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration); - /* start it */ - W(RGF_DMA_ITR_CNT_CRL, - BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK); -} - #undef W -void wil_configure_interrupt_moderation(struct wil6210_priv *wil) -{ - wil_dbg_irq(wil, "%s()\n", __func__); - - /* disable interrupt moderation for monitor - * to get better timestamp precision - */ - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) - return; - - if (test_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities)) - wil_configure_interrupt_moderation_new(wil); - else { - /* Advanced interrupt moderation is not available before - * Sparrow v2. Will use legacy interrupt moderation - */ - wil_configure_interrupt_moderation_lgc(wil); - } -} - static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -253,7 +226,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) trace_wil6210_irq_rx(isr); wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); - if (!isr) { + if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: RX\n"); return IRQ_NONE; } @@ -266,17 +239,18 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) * action is always the same - should empty the accumulated * packets from the RX ring. */ - if (isr & (BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH)) { + if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE | + BIT_DMA_EP_RX_ICR_RX_HTRSH))) { wil_dbg_irq(wil, "RX done\n"); - if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH) + if (unlikely(isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)) wil_err_ratelimited(wil, "Received \"Rx buffer is in risk of overflow\" interrupt\n"); isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); - if (test_bit(wil_status_reset_done, wil->status)) { - if (test_bit(wil_status_napi_en, wil->status)) { + if (likely(test_bit(wil_status_reset_done, wil->status))) { + if (likely(test_bit(wil_status_napi_en, wil->status))) { wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_rx); @@ -289,7 +263,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) } } - if (isr) + if (unlikely(isr)) wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); /* Rx IRQ will be enabled when NAPI processing finished */ @@ -313,19 +287,19 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) trace_wil6210_irq_tx(isr); wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); - if (!isr) { + if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: TX\n"); return IRQ_NONE; } wil6210_mask_irq_tx(wil); - if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { + if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) { wil_dbg_irq(wil, "TX done\n"); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); - if (test_bit(wil_status_reset_done, wil->status)) { + if (likely(test_bit(wil_status_reset_done, wil->status))) { wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_tx); @@ -334,7 +308,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) } } - if (isr) + if (unlikely(isr)) wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); /* Tx IRQ will be enabled when NAPI processing finished */ @@ -368,6 +342,25 @@ static void wil_cache_mbox_regs(struct wil6210_priv *wil) wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); } +static bool wil_validate_mbox_regs(struct wil6210_priv *wil) +{ + size_t min_size = sizeof(struct wil6210_mbox_hdr) + + sizeof(struct wil6210_mbox_hdr_wmi); + + if (wil->mbox_ctl.rx.entry_size < min_size) { + wil_err(wil, "rx mbox entry too small (%d)\n", + wil->mbox_ctl.rx.entry_size); + return false; + } + if (wil->mbox_ctl.tx.entry_size < min_size) { + wil_err(wil, "tx mbox entry too small (%d)\n", + wil->mbox_ctl.tx.entry_size); + return false; + } + + return true; +} + static irqreturn_t wil6210_irq_misc(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -398,7 +391,8 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) if (isr & ISR_MISC_FW_READY) { wil_dbg_irq(wil, "IRQ: FW ready\n"); wil_cache_mbox_regs(wil); - set_bit(wil_status_reset_done, wil->status); + if (wil_validate_mbox_regs(wil)) + set_bit(wil_status_reset_done, wil->status); /** * Actual FW ready indicated by the * WMI_FW_READY_EVENTID @@ -523,11 +517,11 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) /** * pseudo_cause is Clear-On-Read, no need to ACK */ - if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) + if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))) return IRQ_NONE; /* FIXME: IRQ mask debug */ - if (wil6210_debug_irq_mask(wil, pseudo_cause)) + if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause))) return IRQ_NONE; trace_wil6210_irq_pseudo(pseudo_cause); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 1f829541f16e33f74497c8fc7fdb6fff9cdcdc09..ddcc291d0ff7c5af1b49640defed03d3f5f3603a 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,38 +29,6 @@ bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); -static bool no_fw_load = true; -module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); - -static unsigned int tx_interframe_timeout = - WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; - -module_param(tx_interframe_timeout, uint, S_IRUGO); -MODULE_PARM_DESC(tx_interframe_timeout, - " Interrupt moderation TX interframe timeout, usecs."); - -static unsigned int rx_interframe_timeout = - WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; - -module_param(rx_interframe_timeout, uint, S_IRUGO); -MODULE_PARM_DESC(rx_interframe_timeout, - " Interrupt moderation RX interframe timeout, usecs."); - -static unsigned int tx_max_burst_duration = - WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; - -module_param(tx_max_burst_duration, uint, S_IRUGO); -MODULE_PARM_DESC(tx_max_burst_duration, - " Interrupt moderation TX max burst duration, usecs."); - -static unsigned int rx_max_burst_duration = - WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; - -module_param(rx_max_burst_duration, uint, S_IRUGO); -MODULE_PARM_DESC(rx_max_burst_duration, - " Interrupt moderation RX max burst duration, usecs."); - /* if not set via modparam, will be set to default value of 1/8 of * rx ring size during init flow */ @@ -248,7 +216,9 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + if (test_bit(wil_status_fwconnected, wil->status)) { clear_bit(wil_status_fwconnected, wil->status); cfg80211_disconnected(ndev, reason_code, @@ -395,6 +365,8 @@ static void wil_connect_worker(struct work_struct *work) int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); + struct net_device *ndev = wil_to_ndev(wil); + int cid = wil->pending_connect_cid; int ringid = wil_find_free_vring(wil); @@ -409,7 +381,7 @@ static void wil_connect_worker(struct work_struct *work) wil->pending_connect_cid = -1; if (rc == 0) { wil->sta[cid].status = wil_sta_connected; - wil_link_on(wil); + netif_tx_wake_all_queues(ndev); } else { wil->sta[cid].status = wil_sta_unused; } @@ -429,6 +401,7 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->wmi_mutex); mutex_init(&wil->back_rx_mutex); mutex_init(&wil->back_tx_mutex); + mutex_init(&wil->probe_client_mutex); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); @@ -443,10 +416,12 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); + INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); INIT_LIST_HEAD(&wil->back_rx_pending); INIT_LIST_HEAD(&wil->back_tx_pending); + INIT_LIST_HEAD(&wil->probe_client_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); @@ -459,10 +434,10 @@ int wil_priv_init(struct wil6210_priv *wil) goto out_wmi_wq; wil->last_fw_recovery = jiffies; - wil->tx_interframe_timeout = tx_interframe_timeout; - wil->rx_interframe_timeout = rx_interframe_timeout; - wil->tx_max_burst_duration = tx_max_burst_duration; - wil->rx_max_burst_duration = rx_max_burst_duration; + wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; + wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; + wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; + wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; @@ -509,6 +484,8 @@ void wil_priv_deinit(struct wil6210_priv *wil) cancel_work_sync(&wil->back_rx_worker); wil_back_tx_flush(wil); cancel_work_sync(&wil->back_tx_worker); + wil_probe_client_flush(wil); + cancel_work_sync(&wil->probe_client_worker); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } @@ -539,8 +516,6 @@ static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; - bool is_reset_v2 = test_bit(hw_capability_reset_v2, - wil->hw_capabilities); wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); @@ -551,82 +526,67 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); + /* clear all boot loader "ready" bits */ + W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); - if (is_reset_v2) { - S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); - /* XTAL stabilization should take about 3ms */ - usleep_range(5000, 7000); - x = R(RGF_CAF_PLL_LOCK_STATUS); - if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { - wil_err(wil, "Xtal stabilization timeout\n" - "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); - return -ETIME; - } - /* switch 10k to XTAL*/ - C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); - /* 40 MHz */ - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); - - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); + S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + /* XTAL stabilization should take about 3ms */ + usleep_range(5000, 7000); + x = R(RGF_CAF_PLL_LOCK_STATUS); + if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { + wil_err(wil, "Xtal stabilization timeout\n" + "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); + return -ETIME; } + /* switch 10k to XTAL*/ + C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + /* 40 MHz */ + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, - is_reset_v2 ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); - } + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); - /* reset A2 PCIE AHB */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } else { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ - /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. typical time is 200..250 msec */ + /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_HW_MACHINE_STATE); + x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", x); return -ETIME; } - } while (x != HW_MACHINE_BOOT_DONE); - - if (!is_reset_v2) - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + } while (!(x & BIT_BL_READY)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + /* enable fix for HW bug related to the SA/DA swap in AP Rx */ + S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | + BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } -#undef R -#undef W -#undef S -#undef C - void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { le32_to_cpus(&r->base); @@ -636,6 +596,32 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) le32_to_cpus(&r->head); } +static int wil_get_bl_info(struct wil6210_priv *wil) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct RGF_BL bl; + + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); + le32_to_cpus(&bl.ready); + le32_to_cpus(&bl.version); + le32_to_cpus(&bl.rf_type); + le32_to_cpus(&bl.baseband_type); + + if (!is_valid_ether_addr(bl.mac_address)) { + wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); + return -EINVAL; + } + + ether_addr_copy(ndev->perm_addr, bl.mac_address); + if (!is_valid_ether_addr(ndev->dev_addr)) + ether_addr_copy(ndev->dev_addr, bl.mac_address); + wil_info(wil, + "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", + bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); + + return 0; +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -656,7 +642,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) * After calling this routine, you're expected to reload * the firmware. */ -int wil_reset(struct wil6210_priv *wil) +int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; @@ -694,30 +680,36 @@ int wil_reset(struct wil6210_priv *wil) if (rc) return rc; - if (!no_fw_load) { - wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME); + rc = wil_get_bl_info(wil); + if (rc) + return rc; + + if (load_fw) { + wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME, + WIL_FW2_NAME); + wil_halt_cpu(wil); /* Loading f/w from the file */ rc = wil_request_firmware(wil, WIL_FW_NAME); + if (rc) + return rc; + rc = wil_request_firmware(wil, WIL_FW2_NAME); if (rc) return rc; - /* clear any interrupts which on-card-firmware may have set */ + /* Mark FW as loaded from host */ + S(RGF_USER_USAGE_6, 1); + + /* clear any interrupts which on-card-firmware + * may have set + */ wil6210_clear_irq(wil); - { /* CAF_ICR - clear and mask */ - u32 a = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, ICR); - u32 m = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, IMV); - u32 icr = ioread32(wil->csr + a); - - iowrite32(icr, wil->csr + a); /* W1C */ - iowrite32(~0, wil->csr + m); - wmb(); /* wait for completion */ - } + /* CAF_ICR - clear and mask */ + /* it is W1C, clear by writing back same value */ + S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + wil_release_cpu(wil); - } else { - wil_info(wil, "Use firmware from on-card flash\n"); } /* init after reset */ @@ -725,15 +717,22 @@ int wil_reset(struct wil6210_priv *wil) INIT_COMPLETION(wil->wmi_ready); INIT_COMPLETION(wil->wmi_call); - wil_configure_interrupt_moderation(wil); - wil_unmask_irq(wil); + if (load_fw) { + wil_configure_interrupt_moderation(wil); + wil_unmask_irq(wil); - /* we just started MAC, wait for FW ready */ - rc = wil_wait_for_fw_ready(wil); + /* we just started MAC, wait for FW ready */ + rc = wil_wait_for_fw_ready(wil); + } return rc; } +#undef R +#undef W +#undef S +#undef C + void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); @@ -741,28 +740,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil) schedule_work(&wil->fw_error_worker); } -void wil_link_on(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_carrier_on(ndev); - wil_dbg_misc(wil, "netif_tx_wake : link on\n"); - netif_tx_wake_all_queues(ndev); -} - -void wil_link_off(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_tx_stop_all_queues(ndev); - wil_dbg_misc(wil, "netif_tx_stop : link off\n"); - netif_carrier_off(ndev); -} - int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); @@ -771,7 +748,7 @@ int __wil_up(struct wil6210_priv *wil) WARN_ON(!mutex_is_locked(&wil->mutex)); - rc = wil_reset(wil); + rc = wil_reset(wil, true); if (rc) return rc; @@ -878,7 +855,7 @@ int __wil_down(struct wil6210_priv *wil) if (!iter) wil_err(wil, "timeout waiting for idle FW/HW\n"); - wil_rx_fini(wil); + wil_reset(wil, false); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 75bff317b20ce53e52e3e2a83727a5de9570ce0e..2533101d90e819036517415a6f393a6287593aee 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,6 @@ */ #include - #include "wil6210.h" #include "txrx.h" @@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) return min(tx_done, budget); } +static void wil_dev_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; +} + void *wil_if_alloc(struct device *dev, void __iomem *csr) { struct net_device *ndev; @@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", ether_setup); + ndev = alloc_netdev(0, "wlan%d", wil_dev_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; @@ -174,7 +179,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, WIL6210_NAPI_BUDGET); - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); return wil; @@ -217,8 +222,6 @@ int wil_if_add(struct wil6210_priv *wil) return rc; } - wil_link_off(wil); - return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 465175435134fb663646c8bd14bac9c2d6359eb4..9bb1e5b47169da5992fc6348e3a7a741c7a857ad 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -39,18 +39,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) bitmap_zero(wil->hw_capabilities, hw_capability_last); switch (rev_id) { - case JTAG_DEV_ID_MARLON_B0: - wil->hw_name = "Marlon B0"; - wil->hw_version = HW_VER_MARLON_B0; - break; - case JTAG_DEV_ID_SPARROW_A0: - wil->hw_name = "Sparrow A0"; - wil->hw_version = HW_VER_SPARROW_A0; - break; - case JTAG_DEV_ID_SPARROW_A1: - wil->hw_name = "Sparrow A1"; - wil->hw_version = HW_VER_SPARROW_A1; - break; case JTAG_DEV_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; wil->hw_version = HW_VER_SPARROW_B0; @@ -62,13 +50,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) } wil_info(wil, "Board hardware is %s\n", wil->hw_name); - - if (wil->hw_version >= HW_VER_SPARROW_A0) - set_bit(hw_capability_reset_v2, wil->hw_capabilities); - - if (wil->hw_version >= HW_VER_SPARROW_B0) - set_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities); } void wil_disable_irq(struct wil6210_priv *wil) @@ -152,7 +133,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) /* need reset here to obtain MAC */ mutex_lock(&wil->mutex); - rc = wil_reset(wil); + rc = wil_reset(wil, false); mutex_unlock(&wil->mutex); if (debug_fw) rc = 0; @@ -307,7 +288,6 @@ static void wil_pcie_remove(struct pci_dev *pdev) } static const struct pci_device_id wil6210_pcie_ids[] = { - { PCI_DEVICE(0x1ae9, 0x0301) }, { PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { /* end: all zeroes */ }, diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 552209227de9ce96efbe964dae9fc752fc4eb5e6..ca10dcf0986eaa39faeed4f61d8a90189a224376 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -292,6 +292,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) u16 agg_timeout = req->ba_timeout; u16 status = WLAN_STATUS_SUCCESS; u16 ssn = req->ba_seq_ctrl >> 4; + struct wil_tid_ampdu_rx *r; int rc; might_sleep(); @@ -328,11 +329,10 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) return; /* apply */ + r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); spin_lock_bh(&sta->tid_rx_lock); - wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); - sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); - + sta->tid_rx[tid] = r; spin_unlock_bh(&sta->tid_rx_lock); } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b58ee52e1860852f717d6cb91dce40b64be3cb94..1f7da54b8bba2594f71da5b92d45cb921a5fed22 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -53,34 +53,38 @@ static inline int wil_vring_is_full(struct vring *vring) return wil_vring_next_tail(vring) == vring->swhead; } -/* - * Available space in Tx Vring - */ -static inline int wil_vring_avail_tx(struct vring *vring) +/* Used space in Tx Vring */ +static inline int wil_vring_used_tx(struct vring *vring) { u32 swhead = vring->swhead; u32 swtail = vring->swtail; - int used = (vring->size + swhead - swtail) % vring->size; + return (vring->size + swhead - swtail) % vring->size; +} - return vring->size - used - 1; +/* Available space in Tx Vring */ +static inline int wil_vring_avail_tx(struct vring *vring) +{ + return vring->size - wil_vring_used_tx(vring) - 1; } -/** - * wil_vring_wmark_low - low watermark for available descriptor space - */ +/* wil_vring_wmark_low - low watermark for available descriptor space */ static inline int wil_vring_wmark_low(struct vring *vring) { return vring->size/8; } -/** - * wil_vring_wmark_high - high watermark for available descriptor space - */ +/* wil_vring_wmark_high - high watermark for available descriptor space */ static inline int wil_vring_wmark_high(struct vring *vring) { return vring->size/4; } +/* wil_val_in_range - check if value in [min,max) */ +static inline bool wil_val_in_range(int val, int min, int max) +{ + return val >= min && val < max; +} + static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) { struct device *dev = wil_to_dev(wil); @@ -98,8 +102,7 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) vring->va = NULL; return -ENOMEM; } - /* - * vring->va should be aligned on its size rounded up to power of 2 + /* vring->va should be aligned on its size rounded up to power of 2 * This is granted by the dma_alloc_coherent */ vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); @@ -346,27 +349,6 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, } } -/* - * Fast swap in place between 2 registers - */ -static void wil_swap_u16(u16 *a, u16 *b) -{ - *a ^= *b; - *b ^= *a; - *a ^= *b; -} - -static void wil_swap_ethaddr(void *data) -{ - struct ethhdr *eth = data; - u16 *s = (u16 *)eth->h_source; - u16 *d = (u16 *)eth->h_dest; - - wil_swap_u16(s++, d++); - wil_swap_u16(s++, d++); - wil_swap_u16(s, d); -} - /** * reap 1 frame from @swhead * @@ -386,17 +368,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, unsigned int sz = mtu_max + ETH_HLEN; u16 dmalen; u8 ftype; - u8 ds_bits; int cid; struct wil_net_stats *stats; BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); - if (wil_vring_is_empty(vring)) + if (unlikely(wil_vring_is_empty(vring))) return NULL; _d = &vring->va[vring->swhead].rx; - if (!(_d->dma.status & RX_DMA_STATUS_DU)) { + if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) { /* it is not error, we just reached end of Rx done area */ return NULL; } @@ -416,7 +397,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); - if (dmalen > sz) { + if (unlikely(dmalen > sz)) { wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); kfree_skb(skb); return NULL; @@ -445,14 +426,14 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * in Rx descriptor. If type is not data, it is 802.11 frame as is */ ftype = wil_rxdesc_ftype(d) << 2; - if (ftype != IEEE80211_FTYPE_DATA) { + if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); /* TODO: process it */ kfree_skb(skb); return NULL; } - if (skb->len < ETH_HLEN) { + if (unlikely(skb->len < ETH_HLEN)) { wil_err(wil, "Short frame, len = %d\n", skb->len); /* TODO: process it (i.e. BAR) */ kfree_skb(skb); @@ -463,9 +444,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * and in case of error drop the packet * higher stack layers will handle retransmission (if required) */ - if (d->dma.status & RX_DMA_STATUS_L4I) { + if (likely(d->dma.status & RX_DMA_STATUS_L4I)) { /* L4 protocol identified, csum calculated */ - if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) + if (likely((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0)) skb->ip_summed = CHECKSUM_UNNECESSARY; /* If HW reports bad checksum, let IP stack re-check it * For example, HW don't understand Microsoft IP stack that @@ -474,15 +455,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ } - ds_bits = wil_rxdesc_ds_bits(d); - if (ds_bits == 1) { - /* - * HW bug - in ToDS mode, i.e. Rx on AP side, - * addresses get swapped - */ - wil_swap_ethaddr(skb->data); - } - return skb; } @@ -503,7 +475,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) (next_tail != v->swhead) && (count-- > 0); v->swtail = next_tail) { rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); - if (rc) { + if (unlikely(rc)) { wil_err(wil, "Error %d in wil_rx_refill[%d]\n", rc, v->swtail); break; @@ -565,7 +537,7 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) struct vring *v = &wil->vring_rx; struct sk_buff *skb; - if (!v->va) { + if (unlikely(!v->va)) { wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); return; } @@ -671,6 +643,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } memset(txdata, 0, sizeof(*txdata)); + spin_lock_init(&txdata->lock); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -718,8 +691,10 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); + spin_lock_bh(&txdata->lock); + txdata->enabled = 0; /* no Tx can be in progress or start anew */ + spin_unlock_bh(&txdata->lock); /* make sure NAPI won't touch this vring */ - wil->vring_tx_data[id].enabled = 0; if (test_bit(wil_status_napi_en, wil->status)) napi_synchronize(&wil->napi_tx); @@ -873,9 +848,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, d->mac.d[1] = 0; d->mac.d[2] = 0; d->mac.ucode_cmd = 0; - /* use dst index 0 */ - d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | - (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); @@ -938,8 +910,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, return 0; } -static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); struct vring_tx_desc dd, *d = ⅆ @@ -952,21 +924,25 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; uint i = swhead; dma_addr_t pa; + int used; wil_dbg_txrx(wil, "%s()\n", __func__); - if (avail < 1 + nr_frags) { + if (unlikely(!txdata->enabled)) + return -EINVAL; + + if (unlikely(avail < 1 + nr_frags)) { wil_err_ratelimited(wil, - "Tx ring full. No space for %d fragments\n", - 1 + nr_frags); + "Tx ring[%2d] full. No space for %d fragments\n", + vring_index, 1 + nr_frags); return -ENOMEM; } _d = &vring->va[i].tx; pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), - skb->data, &pa); + wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index, + skb_headlen(skb), skb->data, &pa); wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); @@ -976,16 +952,14 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ - if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { - wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n", + if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { + wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; } vring->ctx[i].nr_frags = nr_frags; wil_tx_desc_set_nr_frags(d, nr_frags); - if (nr_frags) - *_d = *d; /* middle segments */ for (; f < nr_frags; f++) { @@ -993,6 +967,10 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); + *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); i = (swhead + f + 1) % vring->size; _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), @@ -1006,13 +984,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * it will succeed here too */ wil_tx_desc_offload_cksum_set(wil, d, skb); - *_d = *d; } /* for the last seg only */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); /* hold reference to skb * to prevent skb release before accounting @@ -1020,15 +1000,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ vring->ctx[i].skb = skb_get(skb); - wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); - - if (wil_vring_is_empty(vring)) /* performance monitoring */ + /* performance monitoring */ + used = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used, used + nr_frags + 1)) { txdata->idle += get_cycles() - txdata->last_idle; + wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", + vring_index, used, used + nr_frags + 1); + } /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); - wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, + vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); @@ -1055,6 +1039,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; } +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) +{ + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + int rc; + + spin_lock(&txdata->lock); + rc = __wil_tx_vring(wil, vring, skb); + spin_unlock(&txdata->lock); + return rc; +} + netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); @@ -1064,18 +1061,18 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) int rc; wil_dbg_txrx(wil, "%s()\n", __func__); - if (!test_bit(wil_status_fwready, wil->status)) { + if (unlikely(!test_bit(wil_status_fwready, wil->status))) { if (!pr_once_fw) { wil_err(wil, "FW not ready\n"); pr_once_fw = true; } goto drop; } - if (!test_bit(wil_status_fwconnected, wil->status)) { + if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { wil_err(wil, "FW not connected\n"); goto drop; } - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { + if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) { wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } @@ -1091,7 +1088,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) else vring = wil_tx_bcast(wil, skb); } - if (!vring) { + if (unlikely(!vring)) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } @@ -1099,7 +1096,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) rc = wil_tx_vring(wil, vring, skb); /* do we still have enough room in the vring? */ - if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) { + if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) { netif_tx_stop_all_queues(wil_to_ndev(wil)); wil_dbg_txrx(wil, "netif_tx_stop : ring full\n"); } @@ -1121,6 +1118,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } +static inline bool wil_need_txstat(struct sk_buff *skb) +{ + struct ethhdr *eth = (void *)skb->data; + + return is_unicast_ether_addr(eth->h_dest) && skb->sk && + (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); +} + +static inline void wil_consume_skb(struct sk_buff *skb, bool acked) +{ + if (unlikely(wil_need_txstat(skb))) + skb_complete_wifi_ack(skb, acked); + else + dev_kfree_skb_any(skb); +} + /** * Clean up transmitted skb's from the Tx VRING * @@ -1138,19 +1151,23 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) int cid = wil->vring2cid_tid[ringid][0]; struct wil_net_stats *stats = &wil->sta[cid].stats; volatile struct vring_tx_desc *_d; + int used_before_complete; + int used_new; - if (!vring->va) { + if (unlikely(!vring->va)) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); return 0; } - if (!txdata->enabled) { + if (unlikely(!txdata->enabled)) { wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); return 0; } wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); + used_before_complete = wil_vring_used_tx(vring); + while (!wil_vring_is_empty(vring)) { int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; @@ -1162,7 +1179,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) /* TODO: check we are not past head */ _d = &vring->va[lf].tx; - if (!(_d->dma.status & TX_DMA_STATUS_DU)) + if (unlikely(!(_d->dma.status & TX_DMA_STATUS_DU))) break; new_swtail = (lf + 1) % vring->size; @@ -1181,16 +1198,16 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) trace_wil6210_tx_done(ringid, vring->swtail, dmalen, d->dma.error); wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n", + ringid, vring->swtail, dmalen, + d->dma.status, d->dma.error); + wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); wil_txdesc_unmap(dev, d, ctx); if (skb) { - if (d->dma.error == 0) { + if (likely(d->dma.error == 0)) { ndev->stats.tx_packets++; stats->tx_packets++; ndev->stats.tx_bytes += skb->len; @@ -1199,8 +1216,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ndev->stats.tx_errors++; stats->tx_errors++; } - - dev_kfree_skb_any(skb); + wil_consume_skb(skb, d->dma.error == 0); } memset(ctx, 0, sizeof(*ctx)); /* There is no need to touch HW descriptor: @@ -1213,8 +1229,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) } } - if (wil_vring_is_empty(vring)) { /* performance monitoring */ - wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid); + /* performance monitoring */ + used_new = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used_new, used_before_complete)) { + wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n", + ringid, used_before_complete, used_new); txdata->last_idle = get_cycles(); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0c5170c023c0fa82ba000b2393cd4346af80fb1d..efbf8fb856524f08dbe084819f6ca4afb8626d61 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,9 +27,11 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; +extern u32 vring_idle_trsh; #define WIL_NAME "wil6210" -#define WIL_FW_NAME "wil6210.fw" +#define WIL_FW_NAME "wil6210.fw" /* code */ +#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ @@ -44,8 +46,9 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) -#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) -#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) +#define WIL_TX_Q_LEN_DEFAULT (4000) +#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) /* limit ring size in range [32..32k] */ #define WIL_RING_SIZE_ORDER_MIN (5) #define WIL_RING_SIZE_ORDER_MAX (15) @@ -77,8 +80,8 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) -#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ -#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */ +#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ +#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ #define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ @@ -119,6 +122,16 @@ struct RGF_ICR { u32 IMC; /* Mask Clear, write 1 to clear */ } __packed; +struct RGF_BL { + u32 ready; /* 0x880A3C bit [0] */ +#define BIT_BL_READY BIT(0) + u32 version; /* 0x880A40 version of the BL struct */ + u32 rf_type; /* 0x880A44 ID of the connected RF */ + u32 baseband_type; /* 0x880A48 ID of the baseband */ + u8 mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */ + u8 pad[2]; +} __packed; + /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_6 (0x880018) @@ -129,6 +142,7 @@ struct RGF_ICR { #define RGF_USER_MAC_CPU_0 (0x8801fc) #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) +#define RGF_USER_BL (0x880A3C) /* Boot Loader */ #define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_CLKS_CTL_0 (0x880abc) #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */ @@ -168,6 +182,13 @@ struct RGF_ICR { #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +/* Offload control (Sparrow B0+) */ +#define RGF_DMA_OFUL_NID_0 (0x881cd4) + #define BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN BIT(0) + #define BIT_DMA_OFUL_NID_0_TX_EXT_TR_EN BIT(1) + #define BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC BIT(2) + #define BIT_DMA_OFUL_NID_0_TX_EXT_A3_SRC BIT(3) + /* New (sparrow v2+) interrupt moderation control */ #define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40) #define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34) @@ -228,16 +249,10 @@ struct RGF_ICR { #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ - #define JTAG_DEV_ID_MARLON_B0 (0x0612072f) - #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f) - #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f) #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) enum { HW_VER_UNKNOWN, - HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */ - HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */ - HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */ HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ }; @@ -384,6 +399,7 @@ struct vring_tx_data { u16 agg_timeout; u8 agg_amsdu; bool addba_in_progress; /* if set, agg_xxx is for request in progress */ + spinlock_t lock; }; enum { /* for wil6210_priv.status */ @@ -480,8 +496,6 @@ enum { }; enum { - hw_capability_reset_v2 = 0, - hw_capability_advanced_itr_moderation = 1, hw_capability_last }; @@ -503,6 +517,12 @@ struct wil_back_tx { u16 agg_timeout; }; +struct wil_probe_client_req { + struct list_head list; + u64 cookie; + u8 cid; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -520,7 +540,7 @@ struct wil6210_priv { wait_queue_head_t wq; /* for all wait_event() use */ /* profile */ u32 monitor_flags; - u32 secure_pcp; /* create secure PCP? */ + u32 privacy; /* secure connection? */ int sinfo_gen; /* interrupt moderation */ u32 tx_max_burst_duration; @@ -563,6 +583,10 @@ struct wil6210_priv { struct list_head back_tx_pending; struct mutex back_tx_mutex; /* protect @back_tx_pending */ struct work_struct back_tx_worker; + /* keep alive */ + struct list_head probe_client_pending; + struct mutex probe_client_mutex; /* protect @probe_client_pending */ + struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; @@ -642,11 +666,9 @@ int wil_if_add(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); -int wil_reset(struct wil6210_priv *wil); +int wil_reset(struct wil6210_priv *wil, bool no_fw); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); -void wil_link_on(struct wil6210_priv *wil); -void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int __wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); @@ -655,6 +677,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); +void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, @@ -721,6 +744,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_stop(struct wil6210_priv *wil); void wil6210_disconnect(struct wil6210_priv *wil, void *bssid, u16 reason_code, bool from_event); +void wil_probe_client_flush(struct wil6210_priv *wil); +void wil_probe_client_worker(struct work_struct *work); int wil_rx_init(struct wil6210_priv *wil, u16 size); void wil_rx_fini(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c8ac1a17c181836f0eecc65189760c96c91415c4..df9017c5c390f88d4639500fd9f09ac0fc116461 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -113,13 +113,15 @@ static u32 wmi_addr_remap(u32 x) /** * Check address validity for WMI buffer; remap if needed * @ptr - internal (linker) fw/ucode address + * @size - if non zero, validate the block does not + * exceed the device memory (bar) * * Valid buffer should be DWORD aligned * * return address for accessing buffer from the host; * if buffer is not valid, return NULL. */ -void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) +void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size) { u32 off; u32 ptr = le32_to_cpu(ptr_); @@ -134,10 +136,17 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) off = HOSTADDR(ptr); if (off > WIL6210_MEM_SIZE - 4) return NULL; + if (size && ((off + size > WIL6210_MEM_SIZE) || (off + size < off))) + return NULL; return wil->csr + off; } +void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) +{ + return wmi_buffer_block(wil, ptr_, 0); +} + /** * Check address validity */ @@ -194,7 +203,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) void __iomem *head = wmi_addr(wil, r->head); uint retry; - if (sizeof(cmd) + len > r->entry_size) { + if (len > r->entry_size - sizeof(cmd)) { wil_err(wil, "WMI size too large: %d bytes, max is %d\n", (int)(sizeof(cmd) + len), r->entry_size); return -ERANGE; @@ -281,7 +290,6 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) /*=== Event handlers ===*/ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wmi_ready_event *evt = d; @@ -290,11 +298,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, evt->mac, wil->n_mids); - - if (!is_valid_ether_addr(ndev->dev_addr)) { - memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); - memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); - } + /* ignore MAC address, we already have it from the boot loader */ snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), "%d", wil->fw_version); } @@ -567,7 +571,6 @@ static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize) static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; u8 cid = evt->cid; @@ -581,7 +584,6 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) wil->sta[cid].data_port_open = true; if (agg_wsize >= 0) wil_addba_tx_cid(wil, cid, agg_wsize); - netif_carrier_on(ndev); } static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) @@ -882,7 +884,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) struct wmi_pcp_started_event evt; } __packed reply; - if (!wil->secure_pcp) + if (!wil->privacy) cmd.disable_sec = 1; if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) || @@ -1028,10 +1030,18 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) { int rc; u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; - struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); + struct wmi_set_appie_cmd *cmd; + + if (len < ie_len) { + rc = -EINVAL; + goto out; + } - if (!cmd) - return -ENOMEM; + cmd = kzalloc(len, GFP_KERNEL); + if (!cmd) { + rc = -ENOMEM; + goto out; + } if (!ie) ie_len = 0; @@ -1042,6 +1052,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len); kfree(cmd); +out: return rc; } @@ -1134,12 +1145,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) return rc; } -int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) +int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) { int rc; struct wmi_temp_sense_cmd cmd = { - .measure_marlon_m_en = cpu_to_le32(!!t_m), - .measure_marlon_r_en = cpu_to_le32(!!t_r), + .measure_baseband_en = cpu_to_le32(!!t_bb), + .measure_rf_en = cpu_to_le32(!!t_rf), + .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW), }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -1151,10 +1163,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) if (rc) return rc; - if (t_m) - *t_m = le32_to_cpu(reply.evt.marlon_m_t1000); - if (t_r) - *t_r = le32_to_cpu(reply.evt.marlon_r_t1000); + if (t_bb) + *t_bb = le32_to_cpu(reply.evt.baseband_t1000); + if (t_rf) + *t_rf = le32_to_cpu(reply.evt.rf_t1000); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index b5102f0b97f435acc5991d63812a2e73f6bed0ad..8a4af613e191856d9db24bb4525b52302358abf5 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -29,8 +29,10 @@ /* General */ #define WILOCITY_MAX_ASSOC_STA (8) +#define WILOCITY_DEFAULT_ASSOC_STA (1) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) +#define WMI_MAX_LOSS_DMG_BEACONS (32) /* List of Commands */ enum wmi_command_id { @@ -48,7 +50,7 @@ enum wmi_command_id { WMI_SET_WSC_STATUS_CMDID = 0x0041, WMI_PXMT_RANGE_CFG_CMDID = 0x0042, WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, - WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, +/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */ WMI_MEM_READ_CMDID = 0x0800, WMI_MEM_WR_CMDID = 0x0801, WMI_ECHO_CMDID = 0x0803, @@ -102,6 +104,8 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x0851, WMI_RS_MGMT_CMDID = 0x0852, WMI_RF_MGMT_CMDID = 0x0853, + WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854, + WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x0862, WMI_NOTIFY_REQ_CMDID = 0x0863, @@ -136,6 +140,7 @@ enum wmi_command_id { WMI_EAPOL_TX_CMDID = 0xf04c, WMI_MAC_ADDR_REQ_CMDID = 0xf04d, WMI_FW_VER_CMDID = 0xf04e, + WMI_PMC_CMDID = 0xf04f, }; /* @@ -283,8 +288,8 @@ enum wmi_scan_type { WMI_LONG_SCAN = 0, WMI_SHORT_SCAN = 1, WMI_PBC_SCAN = 2, - WMI_ACTIVE_SCAN = 3, - WMI_DIRECT_SCAN = 4, + WMI_DIRECT_SCAN = 3, + WMI_ACTIVE_SCAN = 4, }; struct wmi_start_scan_cmd { @@ -374,6 +379,17 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; +/* + * WMI_THERMAL_THROTTLING_CTRL_CMDID + */ +#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) + +struct wmi_thermal_throttling_ctrl_cmd { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_RF_RX_TEST_CMDID */ @@ -648,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action { enum wmi_cfg_rx_chain_cmd_decap_trans_type { WMI_DECAP_TYPE_802_3 = 0, WMI_DECAP_TYPE_NATIVE_WIFI = 1, + WMI_DECAP_TYPE_NONE = 2, }; enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { @@ -785,9 +802,17 @@ struct wmi_echo_cmd { * * Measure MAC and radio temperatures */ + +/* Possible modes for temperature measurement */ +enum wmi_temperature_measure_mode { + TEMPERATURE_USE_OLD_VALUE = 0x1, + TEMPERATURE_MEASURE_NOW = 0x2, +}; + struct wmi_temp_sense_cmd { - __le32 measure_marlon_m_en; - __le32 measure_marlon_r_en; + __le32 measure_baseband_en; + __le32 measure_rf_en; + __le32 measure_mode; } __packed; /* @@ -843,6 +868,7 @@ enum wmi_event_id { WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, + WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, @@ -859,6 +885,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /*P2P*/ + WMI_P2P_CFG_DONE_EVENTID = 0x1910, WMI_PORT_ALLOCATED_EVENTID = 0x1911, WMI_PORT_DELETED_EVENTID = 0x1912, WMI_LISTEN_STARTED_EVENTID = 0x1914, @@ -898,6 +925,15 @@ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; +/* + * WMI_THERMAL_THROTTLING_STATUS_EVENTID + */ +struct wmi_thermal_throttling_status_event { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_GET_STATUS_DONE_EVENTID */ @@ -1154,6 +1190,14 @@ struct wmi_get_pcp_channel_event { u8 reserved[3]; } __packed; +/* + * WMI_P2P_CFG_DONE_EVENTID + */ +struct wmi_p2p_cfg_done_event { + u8 status; /* wmi_fw_status */ + u8 reserved[3]; +} __packed; + /* * WMI_PORT_ALLOCATED_EVENTID */ @@ -1282,8 +1326,8 @@ struct wmi_echo_event { * Measure MAC and radio temperatures */ struct wmi_temp_sense_done_event { - __le32 marlon_m_t1000; - __le32 marlon_r_t1000; + __le32 baseband_t1000; + __le32 rf_t1000; } __packed; #endif /* __WILOCITY_WMI_H__ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/ReleaseNote.txt b/drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt similarity index 85% rename from drivers/net/wireless/bcmdhd_suzuran/ReleaseNote.txt rename to drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt index a1fd76fc81ed9b823bfc04c7b0af23f2e03f2fb0..ca34a2729aa136b287e091d32c655802f6bef25e 100644 --- a/drivers/net/wireless/bcmdhd_suzuran/ReleaseNote.txt +++ b/drivers/net/wireless/bcmdhd_bcm43455/ChangeLog/ReleaseNote.txt @@ -3,16 +3,27 @@ DHD 1.141.X Release for BCM4339, 4354, 43455 SDIO Projects. -------------------------------- Change History -------------------------------- +DHD 1.141.67.33 - 2018-03-09 + - CVE-2017-13292 A-70722061 Fix integer overflow in wl_get_assoc_ies + - CVE-2017-13303 A-71359108 Remove obsoleted wl_cfgvendor_priv_string_handler + +DHD 1.141.67.32 - 2017-12-14 + - Fixed buffer overrun issue in wl_parse_ssid_list_tlv() + - Fixed parsing issue on wl_parse_ssid_list_tlv() for PNO setup + - Fixed memory leak in PNO + - Fixed potential buffer overflow + - Fixed missed SSID/MAC filtering in log for security reason + DHD 1.141.67.30 - 2017.8.31 - Security fix - - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() - - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() - - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() - - CVE-2017-0789 A-37685267 Removed unused SWC feature - - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() - - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() - - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() - - V2017070601 Added P2P IE length check in parsing routine + - CVE-2017-0786 A-37351060 Added boundary check in wl_escan_handler() + - CVE-2017-0787 A-37722970 Added boundary check in dhd_pno_process_epno_result() + - CVE-2017-0788 A-37722328 Added boundary check in dhd_handle_hotlist_scan_evt() + - CVE-2017-0789 A-37685267 Removed unused SWC feature + - CVE-2017-0790 A-37357704 Added boundary check in dhd_process_full_gscan_result() + - CVE-2017-0791 A-37306719 Added event length check in wl_notify_rx_mgmt_frame() + - CVE-2017-0792 A-37305578 Added event length check in dhd_rtt_event_handler() + - V2017070601 Added P2P IE length check in parsing routine DHD 1.141.67.29 - 2017.6.27 - Security fix @@ -25,7 +36,7 @@ DHD 1.141.67.28 - 2017.5.26 - CVE-2016-0802 Code enhancement for prevention of overflow DHD 1.141.67.27 - 2017.3.24 - - Google security fix + - Google security fix - Fix buffer overrun in wl_cfg80211_add_iw_ie, CVE-2017-0567, A-32125310. - Fix buffer overrun in wl_run_escan, CVE-2017-0568, A-34197514. - Fix buffer overrun in dhd_wlfc_reorderinfo_indicate, CVE-2017-0571, A-34203305. @@ -35,7 +46,7 @@ DHD 1.141.67.27 - 2017.3.24 DHD 1.141.67.26 - 2017.2.24 - Google security fix - Prevent buffer overflow of "default_chan_list" in wl_run_escan(). - Google security fix - Check a "results->pkt_count" length not to exceed allocated memory length. - - Google security fix - Removing the unused WEXT file, A-32124445 + - Google security fix - Removing the unused WEXT file, A-32124445 DHD 1.141.67.25 - 2017.1.24 - Google Security Patch - fix possible use-after-free case, A-32838767 @@ -85,18 +96,18 @@ DHD 1.141.67.16 - 2015.11.20 DHD 1.141.67.15 - 2015.11.10 - Additional Android M updates for Loire - - 11mc ftm - - ePNO - - RSSI Monitoring + - 11mc ftm + - ePNO + - RSSI Monitoring - ANQP offload DHD 1.141.67.14 - 2015.11.04 - Android M updates - - Add mkeep_alive feature - - 5GHz Softap - - Gscan Updates - - LinkStat DHD Updates - + - Add mkeep_alive feature + - 5GHz Softap + - Gscan Updates + - LinkStat DHD Updates + DHD 1.141.67.13 - 2015.08.17 - Not to forward BRCM event as a network pkt '0x886c' [CASE# 952625], Shinano 2.1, Kitakami R2,43455 @@ -104,28 +115,28 @@ DHD 1.141.67.12 - 2015.07.15 - Add srl/lrl value setting in Softap, fix the issue not set properly. [CASE# 912911, 930776], Shinano 2.1, Kitakami R2,43455 - Fix for P2P TA issue[ CASE#943732], Kitakami R2, 43455 - Fix for linkstat buffer corruption causing android framework crash [CASE # 940151], Shinano R2.1(4354), Kitakami R2, 43455 - -DHD 1.141.67.11 - 2015.07.08 + +DHD 1.141.67.11 - 2015.07.08 - 4-way handshake delayed when roaming due to uplink traffic (Shinano 2.1 BCM4339 CASE#886484) - Add bcn_to_dly iovar to control link_down event,(Kitakami R2 43455 CASE#912211) - GSCAN fix only for Kitakami R2 43455 - -DHD 1.141.67.10 - 2015.05.29 + +DHD 1.141.67.10 - 2015.05.29 - Add DHD flag to disable 11N proprietary rates. (Kitakami R2 43455 CASE#927300) - Disable TX Beamforming (tx only). (Kitakami R2 43455 CASE#925270) -DHD 1.141.67.9 - 2015.04.30 - - TDLS mgmt build error fix CASE#844655 (CASE#911280) - -DHD 1.141.67.8 - 2015.04.14 +DHD 1.141.67.9 - 2015.04.30 + - TDLS mgmt build error fix CASE#844655 (CASE#911280) + +DHD 1.141.67.8 - 2015.04.14 - Firmware not responding (when running batch scan while in dhcp negotiation (CASE#907419) - Question regarding a huge kmalloc barely used (CASE#903335) - Code questions (CASE#896789) - WL_VENDOR_EXT_SUPPORT definition (CASE#901912) - Release wake lock("wlan_wake") when terminating event thread -DHD 1.141.67.7 - 2015.03.13 - - Use if_counters for connection statistics per interface when available, CSP:892522, Only available in Kitakami R2 43455. +DHD 1.141.67.7 - 2015.03.13 + - Use if_counters for connection statistics per interface when available, CSP:892522, Only available in Kitakami R2 43455. - Fix for ARP stuck issue in multihoming CSP:895926 DHD 1.141.67.6 - 2015.02.03 @@ -141,47 +152,46 @@ DHD 1.141.67.5 - 2015.01.09 - Allow to scan for p2p on passive channel, CSP #868771 - Fix trap in dhd_free(), CSP #874320 - Creating P2P group in available bandwidths in passive channels on 5GHz region, CSP #830497 - + DHD 1.141.67.4 - 2014.12.5 - - Fix build errors caused by Android L updates, - - Fix some warning and potential build error with Kernel 3.8 above. + - Fix build errors caused by Android L updates + - Fix some warning and potential build error with Kernel 3.8 above. DHD 1.141.67.3 - 2014.11.20 (Google L support) - Including android Google L adaptation code (Gscan, Linkstat, Private PNO and RTT which can be selectable in Makefie) - Makefile(Google Android L), Makefile.kk (for Kitkat) - - Enable Dongle memory dump feature. - - Increase max nvram buffer size. - + - Enable Dongle memory dump feature. + - Increase max nvram buffer size. + DHD 1.141.67.2 - 2014.09.05 - Fix for WFA PMF_AP certification. CSP #824822 - Netif packet counters are not updated in wlfc flow control - Adding check routine , wakelock, during softap - - WiFi Direct Certification 5.1.20 change GAS frame handling. - - hostapd ap_info null ptr check added. + - WiFi Direct Certification 5.1.20 change GAS frame handling + - hostapd ap_info null ptr check added DHD 1.141.67.1 - 2014.07.28 - Update Ccode translate table for SOMC - Don't use wlfc info exchange when a device is asleep on SDIO - Increase MAX_CNTL_TX_TIMEOUT to 3 from 2 by specifying it in Makefile. CSP # 800769 - + DHD 1.141.67 - 2014.07.09 - Keep connection while regulatory code change - CSP #803478 - Including action code for tunneled prob req to set wfd ie. CSP # 809533 - MAX_KSO_ATTEMPTS changed to 64, same as R1's - Prevent running wl_event_handler while HANG is occurred - Fix for hostapd buffer free - -DHD 1.141.65 - 2014.06.05 + +DHD 1.141.65 - 2014.06.05 - Fix mmc error at re-loading dhd driver CSP#779847 - Add supports for tdls management frames CSP#778769 - P2P fails after a driver stop / start in the kernel 3.10 - - Increase assoc_retry_max from 3 to 7 to increase a connection rate in very noisy environmnet. + - Increase assoc_retry_max from 3 to 7 to increase a connection rate in very noisy environmnet. - Added definition SUPPORT_P2P_GO_PS in checking bus_sleep code - - Fix multi-AC detection logic to look at rx packets as well as tx packets - -DHD 1.141.60 - 2014.05.16 + - Fix multi-AC detection logic to look at rx packets as well as tx packets +DHD 1.141.60 - 2014.05.16 - CSP 791385, tdls auto enable delete in Makefile - CSP 796606, SOFTAP WPS tethering issue fixed - CSP:779847 Fix mmc error at re-loading dhd driver @@ -198,16 +208,14 @@ DHD 1.141.60 - 2014.05.16 - Packet was freed before both proptxstatus and txcomplete finished - Fix chanspec mismatch - Fix multicast recive in P2P mode - - Kernel 3.14 support + - Kernel 3.14 support - Remove the duplicated kfree of ndev->ieee80211_ptr pointer in wl_dealloc_netinfo - Prevent the RTNL assertion when calling the cfg80211_unregister_wdev function while dhd_module_cleanup - Remove the kernel version dependency in case of using wl_cfg80211_remove_if in wl_cfg80211_handle_ifdel function. - Country/Revision is not initialized after Wi-Fi off->on - Fix the incorrect channel extraction from chanspec when 0 is given as a control channel while scanning - Supporting WNM Notification for HS20 REL2 - - Applying Interaction with MFP by Spec HS2.0 REL2 - + - Applying Interaction with MFP by Spec HS2.0 REL2 2014.03.19 - DHD 1.141.48 - Initial Release for Shinano R2, BCM4339 & BCM4354 - diff --git a/drivers/net/wireless/bcmdhd_suzuran/Kconfig b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig old mode 100755 new mode 100644 similarity index 58% rename from drivers/net/wireless/bcmdhd_suzuran/Kconfig rename to drivers/net/wireless/bcmdhd_bcm43455/Kconfig index 33e379e9ecb769cd9e48a4164302c8e435f8113a..626e47e6d2143659173cb583dc0299866ffea61d --- a/drivers/net/wireless/bcmdhd_suzuran/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm43455/Kconfig @@ -1,4 +1,9 @@ -config BCMDHD_SUZURAN +menuconfig BCMDHD_BCM43455 + tristate "Broadcom wireless cards support" + +if BCMDHD_BCM43455 + +config BCMDHD tristate "Broadcom 43xx wireless cards support" depends on MMC && CFG80211 ---help--- @@ -8,36 +13,57 @@ config BCMDHD_SUZURAN If you choose to build a module, it'll be called dhd. Say M if unsure. +choice + prompt "Select Broadcom wireless card" + depends on BCMDHD + default BCM43455 + +config BCM4339 + bool "Broadcom 4339 wireless card support" + depends on BCMDHD + ---help--- + This module adds support for wireless adapters based on + Broadcom 4339 chipset. + +#config BCM4354 +# bool "Broadcom 4354 wireless card support" +# depends on BCMDHD +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. + config BCM43455 bool "Broadcom 43455 wireless cards support" - depends on BCMDHD_SUZURAN + depends on BCMDHD ---help--- This module adds support for wireless adapters based on Broadcom 43455 chipset. +endchoice + config BCMDHD_FW_PATH - depends on BCMDHD_SUZURAN + depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH - depends on BCMDHD_SUZURAN + depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. config DHD_USE_STATIC_BUF bool "Enable memory preallocation" - depends on BCMDHD_SUZURAN + depends on BCMDHD default n ---help--- Use memory preallocated in platform config BCMDHD_HW_OOB - depends on BCMDHD_SUZURAN + depends on BCMDHD bool "Use H/W OOB to the Host Wakeup" default y ---help--- @@ -45,13 +71,15 @@ config BCMDHD_HW_OOB config DHD_USE_SCHED_SCAN bool "Use CFG80211 sched scan" - depends on BCMDHD_SUZURAN && CFG80211 + depends on BCMDHD && CFG80211 default n ---help--- Use CFG80211 sched scan config BROADCOM_WIFI_RESERVED_MEM bool "BROADCOM Reserved memory for wifi device" - depends on BCMDHD_SUZURAN + depends on BCMDHD ---help--- This is a configuration for broadcom WLAN driver. + +endif diff --git a/drivers/net/wireless/bcmdhd_bcm43455/Makefile b/drivers/net/wireless/bcmdhd_bcm43455/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7470e87cd211493449aa923b7004d05d2c163544 --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile @@ -0,0 +1,402 @@ +# bcmdhd + +##################### +# SDIO Basic feature +##################### +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DBDC -DOOB_INTR_ONLY \ + -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG \ + -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ + -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ + -DCONFIG_DTS + +#################### +# Common feature +#################### +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For Kernel ver > 3.6 or Kernel Patch required +DHDCFLAGS += -DWL_SUPPORT_CHAN_BW + +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# DPC priority +#DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# idle count +DHDCFLAGS += -DDHD_USE_IDLECOUNT + +# custom specific value define +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# set keep alive period +ifneq ($(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING),) +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=$(CONFIG_SOMC_WLAN_KEEP_ALIVE_SETTING) +else +DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=55000 +endif +# set roam setting values +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +# SKB TAILPAD to avoid out of boundary memory access +DHDCFLAGS += -DDHDENABLE_TAILPAD + +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS + +DHDCFLAGS += -DSUPPORT_P2P_GO_PS + +# Disable TXBF sending +DHDCFLAGS += -DDISABLE_TXBFR + +DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# Disable to delay link down event +DHDCFLAGS += -DDISABLE_BCN_DLY + +############################## +# Android Platform Definition +############################## +BCM_SRC_DIR := ./ + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS +# To support p2p private command on kernel 3.8 or above +DHDCFLAGS += -DWL_NEWCFG_PRIVCMD_SUPPORT + +ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD +endif + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +ifneq ($(CONFIG_BCM4339),) +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM43455),) +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o +endif + +ifneq ($(CONFIG_BCM4354),) +# To support RTT +DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +#DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o dhd_rtt.o +endif + + +######################### +# Chip dependent feature +######################### +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB -DSUPPORT_MULTIPLE_REVISION + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + +# tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DREPEAT_READFRAME + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +# DRIVER_TYPE = y +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP + DHDCFLAGS += -DDISABLE_IF_COUNTERS + + # for 4339 only currently - need test for 4354, 43455 + DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 +endif + +ifneq ($(CONFIG_BCM43455),) + DHDCFLAGS += -DBCM43455_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM43455),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_11N_PROPRIETARY_RATES + + # For setting custom short & long retry limit + DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + + # Radio_stat v2 - data structure is updated + DHDCFLAGS += -DLINKSTAT_V2 + +# DHDCFLAGS += -DWL_ABORT_SCAN +endif + +# Read custom mac address function +DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE + +# Default Beacon timeout +ifneq ($(CONFIG_SOMC_WLAN_BCN_TIMEOUT),) + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=$(CONFIG_SOMC_WLAN_BCN_TIMEOUT) +else + DHDCFLAGS += -DSOMC_WLAN_BCN_TIMEOUT=3 +endif + +# The number of the maximum devices which phone can associate +DHDCFLAGS += -DSOMC_MAX_ASSOC_NUM=10 + +# Default Listen Interval in Beacons +ifneq ($(CONFIG_SOMC_WLAN_LISTEN_INTERVAL),) + DHDCFLAGS += -DCUSTOM_LISTEN_INTERVAL=$(CONFIG_SOMC_WLAN_LISTEN_INTERVAL) +endif + +# WAPI +DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI + +# Set the number of probe requests per channel +ifneq ($(CONFIG_SOMC_WLAN_SCAN_NPROBES),) + DHDCFLAGS += -DSOMC_WLAN_SCAN_NPROBES=$(CONFIG_SOMC_WLAN_SCAN_NPROBES) +endif + +# Set default nvram path +ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" +endif + +# Change scan time +ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) + DHDCFLAGS += -DCHANGE_SCAN_TIME +endif + +#EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +MODNAME := wlan + +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ + dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ + hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ + dhd_somc_custom.o + +DHDOFILES += $(ANDROID_OFILES) + +# Module information used by KBuild framework +obj-$(CONFIG_BCMDHD_BCM43455) += $(MODNAME).o + +$(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.N old mode 100755 new mode 100644 similarity index 94% rename from drivers/net/wireless/bcmdhd_suzuran/Makefile rename to drivers/net/wireless/bcmdhd_bcm43455/Makefile.N index 58940b8b57101456d38efe2f0e12efca124bce45..b2d2f597ad786883d5e2c04063f0a9a6d4f701d1 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.N @@ -1,4 +1,4 @@ -# bcmdhd_suzuran +# bcmdhd ##################### # SDIO Basic feature @@ -130,7 +130,6 @@ DHDCFLAGS += -DDISABLE_BCN_DLY ############################## # Android Platform Definition ############################## -#ABSOLUTE_BCM_SRC_DIR := $(WLAN_ROOT)/bcmdhd_suzuran BCM_SRC_DIR := ./ ############################### @@ -199,8 +198,6 @@ ANDROID_OFILES := wl_cfgvendor.o endif - - ######################### # Chip dependent feature ######################### @@ -387,49 +384,31 @@ ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) DHDCFLAGS += -DCHANGE_SCAN_TIME endif +# Get country code +#DHDCFLAGS += -DCUSTOM_FORCE_NODFS_FLAG + +# Enable to use Ukraine CODE (UA/999) +DHDCFLAGS += -DENABLE_80211AC_FOR_UA + #EXTRA_LDFLAGS += --strip-debug EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) -MODNAME := bcmdhd - -DHDOFILES := bcmsdh.o \ - bcmsdh_linux.o \ - bcmsdh_sdmmc.o \ - bcmsdh_sdmmc_linux.o \ - dhd_cdc.o \ - dhd_cfg80211.o \ - dhd_common.o \ - dhd_custom_gpio.o \ - dhd_ip.o \ - dhd_linux.o \ - dhd_linux_sched.o \ - dhd_sdio.o \ - dhd_pno.o \ - dhd_wlfc.o \ - dhd_linux_wq.o \ - aiutils.o \ - bcmevent.o \ - bcmutils.o \ - bcmwifi_channels.o \ - hndpmu.o \ - linux_osl.o \ - sbutils.o \ - siutils.o \ - wldev_common.o \ - wl_cfg_btcoex.o \ - wl_android.o \ - wl_cfg80211.o \ - wl_cfgp2p.o \ - wl_linux_mon.o \ - dhd_linux_platdev.o \ - dhd_somc_custom.o +MODNAME := wlan + +DHDOFILES := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_sdio.o dhd_pno.o dhd_wlfc.o \ + dhd_linux_wq.o aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o \ + hndpmu.o linux_osl.o sbutils.o siutils.o wldev_common.o wl_cfg_btcoex.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_linux_platdev.o \ + dhd_somc_custom.o DHDOFILES += $(ANDROID_OFILES) # Module information used by KBuild framework -obj-$(CONFIG_BCMDHD_SUZURAN) += $(MODNAME).o +obj-$(CONFIG_BCMDHD_BCM43455) += $(MODNAME).o $(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.mm b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/Makefile.mm rename to drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm index 4d71dc030274d52e3e3f34082c9bd3e5f561bb82..92de6bba75b47a54fc208e36e4884dc358360f8b --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.mm +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.bcm @@ -1,4 +1,4 @@ -# bcmdhd_suzuran +# bcmdhd ##################### # SDIO Basic feature @@ -356,5 +356,6 @@ DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ DHDOFILES += $(ANDROID_OFILES) -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd.o +obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.kk b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/Makefile.kk rename to drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk index 1c7ab97d065445f49f7bac548359825cb16a258a..a90c3ebe09383980e79d39b1579dfe840444b4d7 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.kk +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.kk @@ -1,4 +1,4 @@ -# bcmdhd_suzuran +# bcmdhd ##################### # SDIO Basic feature @@ -303,5 +303,6 @@ DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ DHDOFILES += $(ANDROID_OFILES) -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd.o +obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd_suzuran/Makefile.lp b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/Makefile.lp rename to drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp index d5d694145526aac4254839ed1ca15365fc44f94a..8e9ef4d2d1f4cf0ad7c21bcb8d6926a5e1cb2d63 --- a/drivers/net/wireless/bcmdhd_suzuran/Makefile.lp +++ b/drivers/net/wireless/bcmdhd_bcm43455/Makefile.lp @@ -1,4 +1,4 @@ -# bcmdhd_suzuran +# bcmdhd ##################### # SDIO Basic feature @@ -347,5 +347,6 @@ DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ DHDOFILES += $(ANDROID_OFILES) -obj-$(CONFIG_BCMDHD_SUZURAN) += bcmdhd.o +obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) + diff --git a/drivers/net/wireless/bcmdhd_suzuran/aiutils.c b/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/aiutils.c rename to drivers/net/wireless/bcmdhd_bcm43455/aiutils.c index 54a0376747c59922d9f4bba5e63965b8f6c07439..e1f833ad28bead50216e74ec905cd2c3b841422a --- a/drivers/net/wireless/bcmdhd_suzuran/aiutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmevent.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c index 1447d2baa9838a76e5a637b62d1252d5250b45e5..3f9f8390424a2a35676e37e9df47669ee721fd3a --- a/drivers/net/wireless/bcmdhd_suzuran/bcmevent.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmevent.c @@ -1,7 +1,7 @@ /* * bcmevent read-only data shared by kernel or app layers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c index 98e561b6c3b3bfd020ef5a95e899abec51e6d55a..ea4edda2c8b3403dd1b1679dd6f07666769e386b --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh.c @@ -2,7 +2,7 @@ * BCMSDH interface glue * implement bcmsdh API for SDIOH driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c index e57a2cfa1869f7ccfe78ab6247be1a59af25d910..5cab16b98d937208d62644bf39a4994bf4169213 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_linux.c @@ -1,7 +1,7 @@ /* * SDIO access interface for drivers - linux specific (pci only) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c index b2a8e8087d8d475c2b0cfefca1654f516f774c11..87aaeee7c10f6b60ce226bac7766c29d1fb1238a --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c index 17c42b4f7ac4a690b8a48b950b8c7b0af51800cb..27a48afb523b6d5f3e976941313f11b8130de0ea --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdh_sdmmc_linux.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c index 5f152518cd8eaf66f118d6a81d4fd3dae4f04556..689115a51b6fccddad3e3e75a70d165a366433d9 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmsdspi_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmsdspi_linux.c @@ -1,7 +1,7 @@ /* * Broadcom SPI Host Controller Driver - Linux Per-port * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c index 19cd1828eaf54dc3da1dd27a847b62cb309331cf..da16dccf71aa31cea43e3bef0af445d4bcbc17e1 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmspibrcm.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmspibrcm.c @@ -1,7 +1,7 @@ /* * Broadcom BCMSDH to gSPI Protocol Conversion Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmutils.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c index 6b1a5f7c0d42835d352988a20cdce20a2a169e6c..0f1631300f95f24e065e02f188615ea47ef850ef --- a/drivers/net/wireless/bcmdhd_suzuran/bcmutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c index 4cc23b825abfa5faae1e74db44383d4ac3d5c3a7..33ec4f8db8609edba5cf6b30161fb23248296292 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h rename to drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h index 9defecab99937def876077cbb2b3175927a05426..82d59f47ba51848062fe123e5c074176052d53c2 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_channels.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_channels.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h rename to drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h index 9a29f929361cd6fc6f792e8a197ddd312a7ba3c8..40852cb02b299d364adc72cf4e2b09d368ecefe5 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmwifi_rates.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmwifi_rates.h @@ -1,7 +1,7 @@ /* * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c b/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c rename to drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c index 3f8e67cd5cf662700c11f44b9d71191f4f131db6..2312c94c4187b7f18d2b4556fcaa93683440de75 --- a/drivers/net/wireless/bcmdhd_suzuran/bcmxtlv.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/bcmxtlv.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/dhd.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd.h index 743fa9c4086328326a2ca2b1d287642772124041..8156ad66c11c64873b3b5e6d53bd6898edf9051a --- a/drivers/net/wireless/bcmdhd_suzuran/dhd.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -263,6 +263,10 @@ typedef struct dhd_pub { int pktfilter_count; wl_country_t dhd_cspec; /* Current Locale info */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + uint dhd_cflags; +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + bool force_country_change; char eventmask[WL_EVENTING_MASK_LEN]; int op_mode; /* STA, HostAPD, WFD, SoftAP */ @@ -584,6 +588,9 @@ extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); extern int dhd_dev_get_feature_set(struct net_device *dev); extern int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); @@ -641,7 +648,13 @@ extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); extern int somc_get_mac_address(unsigned char *buf); #endif /* GET_CUSTOM_MAC_ENABLE */ extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); -extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); +#ifdef CUSTOM_FORCE_NODFS_FLAG +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags); +#else +extern void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c similarity index 95% rename from drivers/net/wireless/bcmdhd/dhd_bta.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c index c4a9835ae332b1cbcfb36c16f68282771d26ed3f..e2a891c1e2f823dbacfb2165250169ab3b68e816 100644 --- a/drivers/net/wireless/bcmdhd/dhd_bta.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.c @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_bta.c 434434 2013-11-06 07:16:02Z $ + * $Id: dhd_bta.c 701450 2017-05-25 02:10:23Z $ */ #error "WLBTAMP is not defined" @@ -51,9 +51,7 @@ int dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) { amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; - uint len = sizeof(buf); - wl_ioctl_t ioc; + int ret; if (cmd_len < HCI_CMD_PREAMBLE_SIZE) return BCME_BADLEN; @@ -61,18 +59,11 @@ dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) return BCME_BADLEN; - len = bcm_mkiovar("HCI_cmd", - (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); + ret = dhd_iovar(pub, 0, "HCI_cmd", (char *)cmd, + (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, NULL, 0, TRUE); - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = TRUE; - - return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); + return ret; } #else /* !SEND_HCI_CMD_VIA_IOCTL */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h index 0c5e9de534e96c38a9410130018ce5c75599a3a0..000d4eee6a5103f1707ef6cc33ec9303852b1715 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h index 14515e12b1e7497b13bf70ba229e50f51e10b597..0887b0ee9bdf0acd9eb89f8927ab571d18ec3ba8 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bus.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_bus.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c index 00d4821d7e5e2656c7d2e144b06ed4b49b8a58ac..153cffbce0b773d65e3bf7066ab4fb2caf23f470 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cdc.c @@ -1,7 +1,7 @@ /* * DHD Protocol Module for CDC and BDC. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c index ed3a7690b342a44e8e5311160ba4d6dd5743f938..bac72e4d560fcbe630474ac5a2e81c6bef795525 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h index a160571ad8c9145796333141091fb3af81cad30f..fbc10f211adc31cb522de0264abb05ae15282ddd --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_common.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c index 5d817e7221f80a02e1efc9902d43d525e12f02ab..0398aba3ebdb034bac551f4b7fa0496d6894d3bb --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_common.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), common DHD core. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 701450 2017-05-25 02:10:23Z $ + * $Id: dhd_common.c 732203 2017-11-16 05:18:28Z $ */ #include #include @@ -78,7 +78,7 @@ int dhd_msg_level = DHD_ERROR_VAL; #if defined(WL_WIRELESS_EXT) #include -#endif +#endif #ifdef SOFTAP char fw_path2[MOD_PARAM_PATHLEN]; @@ -105,7 +105,7 @@ bool ap_fw_loaded = FALSE; /* Version string to report */ #ifdef DHD_DEBUG #ifndef SRCBASE -#define SRCBASE "drivers/net/wireless/bcmdhd_suzuran" +#define SRCBASE "drivers/net/wireless/bcmdhd_bcm43455" #endif #define DHD_COMPILED "\nCompiled in " SRCBASE #endif /* DHD_DEBUG */ @@ -1217,7 +1217,7 @@ wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) int ret; ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); - if (ret != BCME_OK) { + if (ret != BCME_OK && ret != -30) { DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret)); } @@ -2106,13 +2106,18 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte { char* str; int idx = 0; + uint8 len; if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; + return BCME_BADARG; } str = *list_str; while (*bytes_left > 0) { + if (idx >= max) { + DHD_ERROR(("%s number of SSIDs more than %d\n", __FUNCTION__, idx)); + return BCME_BADARG; + } if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { *list_str = str; @@ -2122,9 +2127,14 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte /* Get proper CSCAN_TLV_TYPE_SSID_IE */ *bytes_left -= 1; + if (*bytes_left == 0) { + DHD_ERROR(("%s no length field.\n", __FUNCTION__)); + return BCME_BADARG; + } str += 1; ssid[idx].rssi_thresh = 0; - if (str[0] == 0) { + len = str[0]; + if (len == 0) { /* Broadcast SSID */ ssid[idx].SSID_len = 0; memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); @@ -2132,20 +2142,17 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte str += 1; DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } - else if (str[0] <= DOT11_MAX_SSID_LEN) { + } else if (len <= DOT11_MAX_SSID_LEN) { /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; + ssid[idx].SSID_len = len; *bytes_left -= 1; - str += 1; - /* Get SSID */ if (ssid[idx].SSID_len > *bytes_left) { DHD_ERROR(("%s out of memory range len=%d but left=%d\n", __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; + return BCME_BADARG; } - + str += 1; memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); *bytes_left -= ssid[idx].SSID_len; @@ -2154,16 +2161,11 @@ wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *byte DHD_TRACE(("%s :size=%d left=%d\n", (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } else { + DHD_ERROR(("### SSID size more than %d\n", str[0])); + return BCME_BADARG; } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; - } - - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); - return -1; - } + idx++; } *list_str = str; @@ -2351,4 +2353,4 @@ wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) return num; } -#endif +#endif diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c index 883c1e205db3264cf6bded1e4aed45bbfa5aef22..dcb4e1771d9376202a4bd5844d667fc4d431aa76 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_custom_gpio.c @@ -1,6 +1,6 @@ /* * Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -35,7 +35,7 @@ #include #if defined(WL_WIRELESS_EXT) #include -#endif +#endif #define WL_ERROR(x) printf x #define WL_TRACE(x) @@ -546,7 +546,12 @@ const struct cntry_locales_custom translate_custom_table[] = { * input : ISO 3166-1 country abbreviation * output: customized cspec */ +#ifdef CUSTOM_FORCE_NODFS_FLAG +void get_customized_country_code(void *adapter, char *country_iso_code, + wl_country_t *cspec, u32 flags) +#else void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ { #if 0 && (defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))) @@ -555,7 +560,11 @@ void get_customized_country_code(void *adapter, char *country_iso_code, wl_count if (!cspec) return; +#ifdef CUSTOM_FORCE_NODFS_FLAG + cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, flags); +#else cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ if (cloc_ptr) { strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); cspec->rev = cloc_ptr->custom_locale_rev; diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h index 796d5598acd1759f13d1745a9f3684f874cdeeb5..8216dba67297ed693477ffb0678a8cf831c44948 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_dbg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_dbg.h @@ -1,7 +1,7 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c index b7760c5cd1bb3234c6a3f761b5e53cb708085acf..06167ab86cf83f2be31e9d030ed6cb7e49446d1e --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.c @@ -1,7 +1,7 @@ /* * IP Packet Parser Module. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h index 08765033c0beda38727e36c7d425e4bffe01dfcf..62ce6b5700ff96b3f80b04eb4da9f20a6f2a46fa --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_ip.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_ip.h @@ -3,7 +3,7 @@ * * Provides type definitions and function prototypes used to parse ip packet. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c index c4f6a6461c20b21a7b59271c396ff9ef9a860b12..ac136f6867f6b3cc9faf7a29b34d363b8f966700 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2014 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -3594,6 +3594,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef GET_CUSTOM_MAC_ENABLE wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); #endif /* GET_CUSTOM_MAC_ENABLE */ +#ifdef CUSTOM_FORCE_NODFS_FLAG + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; +#endif #ifdef CUSTOM_COUNTRY_CODE cloc_ptr = wifi_platform_get_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode); if (cloc_ptr) { @@ -4784,7 +4788,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAIBSS setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ +#ifdef SHOW_LOGTRACE setbit(eventmask, WLC_E_TRACE); +#else + clrbit(eventmask, WLC_E_TRACE); +#endif /* SHOW_LOGTRACE */ #ifdef DHD_LOSSLESS_ROAMING setbit(eventmask, WLC_E_ROAM_PREP); #endif /* DHD_LOSSLESS_ROAMING */ @@ -5861,7 +5869,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); @@ -6233,7 +6241,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; + int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); @@ -6553,6 +6561,21 @@ dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num) return ret; } +#ifdef CUSTOM_FORCE_NODFS_FLAG +int +dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (nodfs) + dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; + else + dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; + dhd->pub.force_country_change = TRUE; + return 0; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + #ifdef PNO_SUPPORT /* Linux wrapper to call common dhd_pno_stop_for_ssid */ int @@ -7270,7 +7293,12 @@ void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_c wl_country_t *cspec) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); +#ifdef CUSTOM_FORCE_NODFS_FLAG + get_customized_country_code(dhd->adapter, country_iso_code, cspec, + dhd->pub.dhd_cflags); +#else get_customized_country_code(dhd->adapter, country_iso_code, cspec); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ } void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) { diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h old mode 100755 new mode 100644 similarity index 77% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h index af6517b8de7b0c0e152f01c4d5437144984e4fb6..e97929afe083e3046e0be502f3b264b550c7f496 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux.h @@ -1,7 +1,7 @@ /* * DHD Linux header file (dhd_linux exports for cfg80211 and other components) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -37,6 +37,27 @@ #include #include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#endif +#ifdef CUSTOM_FORCE_NODFS_FLAG +#define WLAN_PLAT_NODFS_FLAG 0x01 +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +#if !defined(CONFIG_WIFI_CONTROL_FUNC) +struct wifi_platform_data { + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG + void *(*get_country_code)(char *ccode, u32 flags); +#else + void *(*get_country_code)(char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ +}; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ typedef struct wifi_adapter_info { @@ -64,7 +85,11 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags); +#else void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c index a25ce6f51beb78fb780b6f41615bc0aa061877b1..3dca697c1f172800e23691179824aa9f9726b3d8 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_platdev.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_platdev.c @@ -1,7 +1,7 @@ /* * Linux platform device for DHD WLAN adapter * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2013 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -47,16 +47,6 @@ #ifdef CONFIG_SOMC_WIFI_CONTROL #include #endif /* CONFIG_SOMC_WIFI_CONTROL */ -#if !defined(CONFIG_WIFI_CONTROL_FUNC) -struct wifi_platform_data { - int (*set_power)(int val); - int (*set_reset)(int val); - int (*set_carddetect)(int val); - void *(*mem_prealloc)(int section, unsigned long size); - int (*get_mac_addr)(unsigned char *buf); - void *(*get_country_code)(char *ccode); -}; -#endif /* CONFIG_WIFI_CONTROL_FUNC */ #define WIFI_PLAT_NAME "bcmdhd_wlan" #define WIFI_PLAT_NAME2 "bcm4329_wlan" @@ -239,7 +229,11 @@ int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) #endif } +#ifdef CUSTOM_FORCE_NODFS_FLAG +void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags) +#else void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) +#endif /* CUSTOM_FORCE_NODFS_FLAG */ { /* get_country_code was added after 2.6.39 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) @@ -251,7 +245,11 @@ void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) DHD_TRACE(("%s\n", __FUNCTION__)); if (plat_data->get_country_code) { +#ifdef CUSTOM_FORCE_NODFS_FLAG /* CUSTOM_COUNTRY_CODE */ + return plat_data->get_country_code(ccode, flags); +#else return plat_data->get_country_code(ccode); +#endif /* CUSTOM_FORCE_NODFS_FLAG */ } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c index 4b62ee40c2f170f38fc0b5cb94a853aba53c7cd7..a24b32124fba215268dfa02481d972e1c56ceb9e --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_sched.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_sched.c @@ -1,7 +1,7 @@ /* * Expose some of the kernel scheduler routines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c index ea4d567b19411ff024765cab199f620fe3bb00a1..bd0b7afad0222054f2cf902fd6eec2ed1278b07d --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h index 1066250b2824de38d29878eff8dd7c458f58eca9..66f237fb7002564fa163e61a0742835c4e067a4b --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_linux_wq.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_linux_wq.h @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c index 5f91924c2580a4bae3a07d653ad7809c21382433..ea97317f040cb60b3d54ea558ed54c8956f87454 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD) * Prefered Network Offload and Wi-Fi Location Service(WLS) code. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -2607,6 +2607,12 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) } plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } mutex_lock(&_pno_state->pno_mutex); diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h index 361c5cecd34da8e4f04944af46f93dc14acf13e9..62425da6c1e61c03cc0ab66f1d9789599bf22185 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_pno.h @@ -1,7 +1,7 @@ /* * Header file of Broadcom Dongle Host Driver (DHD) * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h index 6b95755938bba084d780b181e7efc03619b3ef64..61b95d13a747538fa501ddcd1680e58842066c5c --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_proto.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_proto.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c index d1d29dea61be62f84681a4e0f4d03c9a5dc9738e..b80fffe86ae19c5c374b473eff05a75f02019797 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.c @@ -448,7 +448,7 @@ rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) int rate_rspec2rate(uint32 rspec) { - int rate = -1; + int rate = 0; if (RSPEC_ISLEGACY(rspec)) { rate = 500 * (rspec & WL_RSPEC_RATE_MASK); @@ -474,7 +474,7 @@ rate_rspec2rate(uint32 rspec) ASSERT(0); } - return (rate == 0) ? -1 : rate; + return rate; } char resp_buf[WLC_IOCTL_SMLEN]; @@ -1387,17 +1387,38 @@ static wifi_rate_t dhd_rtt_convert_rate_to_host(uint32 rspec) { wifi_rate_t host_rate; - if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + uint32 bandwidth; + memset(&host_rate, 0, sizeof(wifi_rate_t)); + if (RSPEC_ISLEGACY(rspec)) { host_rate.preamble = 0; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + } else if (RSPEC_ISHT(rspec)) { host_rate.preamble = 2; host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + } else if (RSPEC_ISVHT(rspec)) { host_rate.preamble = 3; host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; } - host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + + bandwidth = RSPEC_BW(rspec); + switch (bandwidth) { + case WL_RSPEC_BW_20MHZ: + host_rate.bw = RTT_RATE_20M; + break; + case WL_RSPEC_BW_40MHZ: + host_rate.bw = RTT_RATE_40M; + break; + case WL_RSPEC_BW_80MHZ: + host_rate.bw = RTT_RATE_80M; + break; + case WL_RSPEC_BW_160MHZ: + host_rate.bw = RTT_RATE_160M; + break; + default: + host_rate.bw = RTT_RATE_20M; + break; + } + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); return host_rate; diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd_rtt.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h index 308f657391a53d3b99aaa007ee27157a59f9bec4..08216dbc8d08cf5b3ad6df3886abd17302aea380 100644 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_rtt.h @@ -128,6 +128,14 @@ enum { RTT_BW_80 = BIT(4), RTT_BW_160 = BIT(5) }; + +enum rtt_rate_bw { + RTT_RATE_20M, + RTT_RATE_40M, + RTT_RATE_80M, + RTT_RATE_160M +}; + #define FTM_MAX_NUM_BURST_EXP 14 #define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) #define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c index 44ec2b607ab8d458ab65cf17abf9c7d092eb38a2..5faca9c508d755f5a927a33ba39157a48a8fe3ae --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2014 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -8146,7 +8146,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) } else bcmerror = BCME_SDIO_ERROR; - dhd_os_sdunlock(dhdp); + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_SDIO_ERROR; DHD_INFO(("%s called when dongle is not in reset\n", diff --git a/drivers/net/wireless/bcmdhd/dhd_somc_custom.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_somc_custom.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.c diff --git a/drivers/net/wireless/bcmdhd/dhd_somc_custom.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_somc_custom.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_somc_custom.h diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c index 52700ac94ff95d343ab3c42e73aca99b35cb8288..1152ce9dfd23e358f6b1e79e9ffdf5d97a29c91b --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.c @@ -1,7 +1,7 @@ /* * DHD PROP_TXSTATUS Module. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h rename to drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h index ee5d00489bd51184f07af173b419ed6ff1c1305d..347c1bcbea461bb73d3d6c2666b8127f54179916 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dhd_wlfc.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h b/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h rename to drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h index 73024f1e427467e774af1627ecbace20a1c61e9d..cd499133dcc76efd7c6f12fd8d6a0f622d3c07a8 --- a/drivers/net/wireless/bcmdhd_suzuran/dngl_stats.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dngl_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h old mode 100755 new mode 100644 similarity index 96% rename from drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h rename to drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h index f5f5148cd5b34ae4743f9aad6ea654f8f425e464..74047430fff4cdfab9198d7ffb90ff23007de439 --- a/drivers/net/wireless/bcmdhd_suzuran/dngl_wlhdr.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/dngl_wlhdr.h @@ -1,7 +1,7 @@ /* * Dongle WL Header definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c b/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/hndpmu.c rename to drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c index 31fcf91f02231e836395832d895bb768777f2edf..cfbbea8a854cb38446f45507ab247419d96e05ac --- a/drivers/net/wireless/bcmdhd_suzuran/hndpmu.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/hndpmu.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/Makefile b/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/Makefile rename to drivers/net/wireless/bcmdhd_bcm43455/include/Makefile index 797ee2563e336b5ef090a128207bc7723dbabfa5..3b8291471203d9d7503cf6d8b62026e4d2b2d3a6 --- a/drivers/net/wireless/bcmdhd_suzuran/include/Makefile +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/Makefile @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 1999-2017, Broadcom Corporation +# Copyright (C) 1999-2018, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h b/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h index 831865dd88171416484d35441d6396f3ffaa8fa8..cc4fe830c965480db51707b7d7acd759220ebfcf --- a/drivers/net/wireless/bcmdhd_suzuran/include/aidmp.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h old mode 100755 new mode 100644 similarity index 96% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h index 7c6e70f449ef38cea86d5a9ed26464048f4ff17c..fe1622268957463491431eb5c82c8e5c521248a4 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_cfg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_cfg.h @@ -1,7 +1,7 @@ /* * BCM common config options * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h index b05ba3704aebf5cf111647fa81b3b10bc5e89c1e..bbb4e6699b73700c843381d27122ac1f30172325 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcm_mpool_pub.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcm_mpool_pub.h @@ -35,7 +35,7 @@ * and instrumentation on top of the heap, without modifying the heap * allocation implementation. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h index c93b6f619b20a3ecf523ce59764053844de4e11f..3759e362f1be15338092dd6acf390aa4203c6221 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmcdc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h index 15c00f718a3197a787d71d3cba6992818d268998..d7a14c094aa5f3c2d1a547255a669fe9b595b669 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdefs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h index ebc57c71d56f8d74c590cb782c057528ce1be71a..d950bc71355e9073b2fbdf4debe1759c6040e6e2 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h index 970989e38f6b0ed117adaaca96d3f8208a41c7c3..3e783eae32be8fb67fd491973c1960f787089b33 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmendian.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h index 3fbc303bd528f1a3296d06bdbf9b9f361434aa02..e4b785c84f4c85a676be44d3ff2db23df49f1a03 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmnvram.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmnvram.h @@ -1,7 +1,7 @@ /* * NVRAM variable manipulation * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h index d4781abb982a6b1460b54d91dc2c6fb016c1398e..49790c24ae220a675226889dd755db40fb4bf67b --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmpcispi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmpcispi.h @@ -1,7 +1,7 @@ /* * Broadcom PCI-SPI Host Controller Register Definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h old mode 100755 new mode 100644 similarity index 96% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h index 84c232f8a05907bf1e9228bc60fb9eff2e09793e..9cc62882fe40cf7096619c49b9260e5216038f1b --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmperf.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h index 4d4634ba65854b2baa99cf98505950af2477ec52..267c974cb33dab444049747e5d17981c13b595d4 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdbus.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdbus.h @@ -2,7 +2,7 @@ * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h index 099120a34d6082c2260faf610aa7ad174ddec08f..9946acfb7ea215f679af09fe8ff8c726d3dcd402 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh.h @@ -3,7 +3,7 @@ * export functions to client drivers * abstract OS and BUS specific details of SDIO * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h index 5ad8ae077270a8a01eed1eb3441ba607b8a28bbd..c98171fd30155ffe92d2064a16743e3684853459 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdh_sdmmc.h @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h index 2bfac6693ec489acc09bcc62d5b503ae4654317c..9c9c32e1ed245e11238daa8b8f3f9bcbce5ff556 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdpcm.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdpcm.h @@ -2,7 +2,7 @@ * Broadcom SDIO/PCMCIA * Software-specific definitions shared between device and host side * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h index 1fc1fd4eef6b4ee7293560d33c58bb70d2dd2c10..559a7c2bb6305e5614d4144361357d8d09448028 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdspi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h index 9edb37286712458c28c4ed0efb528e359452dc3c..318a6a8fc85d03f432c501978461ac17dc38621c --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsdstd.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h index 193dc8e0c9ca40c1fc63142aa0a26b834cbb2e78..0b4d7bdb6d6dec1e123a3d8c2079110b1a2a19d4 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspi.h @@ -1,7 +1,7 @@ /* * Broadcom SPI Low-Level Hardware Driver API * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h index c81e6049ae037f28915c5af056676a519cf3a084..833fd261705d03d86e12ff716adc57d6c86717b4 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmspibrcm.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmspibrcm.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h index 1baebcdf90bb35e32772b6d471d01cacafac8be0..3e485d519581359e07a3f59894a209c0096c91d1 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_fmt.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_fmt.h @@ -1,7 +1,7 @@ /* * SROM format definition. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h index c8335b56eb5f6eeecbd3f2d11b664fc5456085f3..be43a7c5ef183e895f5d76519f1c0855e42ead39 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmsrom_tbl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmsrom_tbl.h @@ -1,7 +1,7 @@ /* * Table that encodes the srom formats for PCI/PCIe NICs. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h index 1743d1f8e92725912c2d1c908b86f3553ba5ba6b..1103739f30f2a3ed0d2acaee445f17ab0132d6f6 --- a/drivers/net/wireless/bcmdhd_suzuran/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h index edb22d53ea84a7c75c44b89fe78054a1478cb844..f17c05d52521a559cc90a6a06f455fa3d95b380b --- a/drivers/net/wireless/bcmdhd_suzuran/include/brcm_nl80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/brcm_nl80211.h @@ -1,7 +1,7 @@ /* * Definitions for nl80211 testmode access to host driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h b/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/dbus.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h index fe898da34ac9449d50c5e965319bbd7ce4be1383..80ef80bd97e96fed2323a33ed6eb70eef5e9acac --- a/drivers/net/wireless/bcmdhd_suzuran/include/dbus.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/dbus.h @@ -2,7 +2,7 @@ * Dongle BUS interface Abstraction layer * target serial buses like USB, SDIO, SPI, etc. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h index 7d7f8c86e99cde2895ffbd52bb1a179313368e67..6001a497ce815f67f4a6524ca476986ce38aa9e5 --- a/drivers/net/wireless/bcmdhd_suzuran/include/devctrl_if/wlioctl_defs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/devctrl_if/wlioctl_defs.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h index 2adfaf89bf1b43fbd1e5a7f9e730841054d297dc..cffb2f3b1de48d625069b4e46197f2cfa32c667e --- a/drivers/net/wireless/bcmdhd_suzuran/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h old mode 100755 new mode 100644 similarity index 87% rename from drivers/net/wireless/bcmdhd_suzuran/include/epivers.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h index 99277f8b9fb9f89417c03bfba6090dd20898297f..d60c79139364ecb5607b8e89cefa81925264cbaa --- a/drivers/net/wireless/bcmdhd_suzuran/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -32,17 +32,17 @@ #define EPI_RC_NUMBER 67 -#define EPI_INCREMENTAL_NUMBER 30 +#define EPI_INCREMENTAL_NUMBER 33 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 141, 67, 30 +#define EPI_VERSION 1, 141, 67, 33 -#define EPI_VERSION_NUM 0x018d431e +#define EPI_VERSION_NUM 0x018d4321 #define EPI_VERSION_DEV 1.141.67 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.141.67.30 (r)" +#define EPI_VERSION_STR "1.141.67.33 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h old mode 100755 new mode 100644 similarity index 96% rename from drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h index 9e236d789f015baa1cca730b9d22d8352ff1cc32..a22f39bbf831e9af715eea560910fe1e6c798182 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndpmu.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h index eee716db5fcfd300907aa104b0cbde92d711139e..5c305023d629e5431804e11ea4e40a5502cf6c82 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_armtrap.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_armtrap.h @@ -1,7 +1,7 @@ /* * HNDRTE arm trap handling. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h index 7dcde5ff37cd4b2fead6d9bbb8ca5d571898db91..40731bf781020d4f9021897ed06acdd44fc1b6a6 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndrte_cons.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndrte_cons.h @@ -1,7 +1,7 @@ /* * Console support for hndrte. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h index 1dbe9c19e0ab04e478d2faa0878ed755ac491946..948f9af92149ee96fef5b0dea830127c05b33ce0 --- a/drivers/net/wireless/bcmdhd_suzuran/include/hndsoc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/hndsoc.h @@ -1,7 +1,7 @@ /* * Broadcom HND chip & on-chip-interconnect-related definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h index d586e5f8ba601f87624ecdff3382aa8590122852..228e231a9955bbb4f4006c538a6d4173b3066418 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -199,7 +199,7 @@ extern int osl_error(int bcmerror); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #else -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ #define printf(fmt, args...) printk(fmt , ## args) #include /* for vsn/printf's */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h b/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h index f6e08bc85f14764592c2cf011bdc80c00adad271..363fb5caa7f536c669ebada160569c93f45adde8 --- a/drivers/net/wireless/bcmdhd_suzuran/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/linuxver.h @@ -2,7 +2,7 @@ * Linux-specific abstractions to gain some independence from linux kernel versions. * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h b/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h index ab6668097ec059c6a2403ed68b47da20e57b0f80..722e5737564a60a41da052feb088bb77a62ae6aa --- a/drivers/net/wireless/bcmdhd_suzuran/include/miniopt.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/miniopt.h @@ -1,7 +1,7 @@ /* * Command line options parser. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h b/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h index 6119bbba09a86d143b454a562cc921439b9b2267..4105585989a4d8bb55f1d2c92f5ba842af5f817f --- a/drivers/net/wireless/bcmdhd_suzuran/include/msgtrace.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/osl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/osl.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/osl.h index 9a1f8a5960b009388ed9e4286dff6382f6a9a64f..7a101e506e88dd02ebf2be5c7d01a62276d6d1c5 --- a/drivers/net/wireless/bcmdhd_suzuran/include/osl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h index 27e39b53e9eb070d143dccfeb7008572b1d61176..cad72104470b31b5f0e8be4a1319b1b4894fa8df --- a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_end.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h index 61c14a69401e1372e1c020c15751a93e47268e43..18f48270fa8c1c8f1a45813c1c8a6dee5e28eda4 --- a/drivers/net/wireless/bcmdhd_suzuran/include/packed_section_start.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include * * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h b/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h index 99ebf063f345989114d0d5f4cbf578c267734500..13774d0e510c2c95aa812a71432bc69ce42fc2db --- a/drivers/net/wireless/bcmdhd_suzuran/include/pcicfg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h index e18cc6ef19d03b0050f7c94f05bde13c5c85b0e5..a501d8206f87932f410693e99b9b9f5b3b55c317 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h index 9de5616ab0240ffb70ecbb4d38f4615c7c4b48bc..7b9baf3c6550bfb218b39f6473883178348b7ce5 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11_bta.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h index ded6b7612415d3f826b0e512dc5837fae9743918..879fa84f3168d7b1bfbdeb7ef9b190aa3de67bba --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.11e.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.11e.h @@ -1,7 +1,7 @@ /* * 802.11e protocol header file * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h index efb390bfc09ec0c3917b34fa926edd59aa966d4e..ceddd5c767d0c380d2dadf8b242b95c577b8d461 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.1d.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.1d.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h index dc1626aa667a9b78949bd9b2894716005ea7432d..e7728e307f0b409dbda73a222b30352d936687ef --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/802.3.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/802.3.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h index 4947e533cb8a22d5123b062a840e45657d11a0e6..8611c682791c4adf986b9cd531f8e778d588f644 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h index 352916ba33a8135af0c2cf650e452e4e0f274438..006213bfff73ba4bc5ca23f12d43720028692763 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h index f5ee807c1c9666b88aed77b6a6c2958de2970339..a95a6131324e47eaa46adfb8706d5b7d4b812411 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmip.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h index 86226102e4553d7fdbe232aeb7471eb1ffc98a0f..42068ef5ebc9263752900ba9baeae7eca1ee8d0b --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmipv6.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmipv6.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h index 850c5b4e8f2f398b5ef9526207c24174d3bfd76d..2be771af44e71250ec0b879e13876c7c6ad8348c --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bcmtcp.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bcmtcp.h @@ -1,7 +1,7 @@ /* * Fundamental constants relating to TCP Protocol * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h index f1ea2909971c84996f4f0b96716bdb7b1b93bf9d..096794592a8e2c1569d376b09a6a5ce3100f2e52 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/bt_amp_hci.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/bt_amp_hci.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h index 549566e589504ff5497e7a2bf4472f34d9333aca..d6a84f24fbc26253fc67917718436ef3b06fdac1 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/dnglevent.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/dnglevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h index ed3310cd37f99bc7bfb36aea0ab2b8f8c3734579..7b012eecb1103111a600084bb0aa3335c59dd9ab --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/eapol.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/eapol.h @@ -5,7 +5,7 @@ * IEEE Std 802.1X-2001 * IEEE 802.1X RADIUS Usage Guidelines * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h index 68eb83f5330b10eff6e33d638a0489e18d607d00..3542492743ec534ef7f2294de798c40d317de627 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/ethernet.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/ethernet.h @@ -1,7 +1,7 @@ /* * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h index f7179b6a3cd498f2f1a3be9d9dc9d7d3b9ed586b..0c2d922a6d77531757f37c4b51ebf20fe36322cc --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/nan.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/nan.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h index 41c037274901f060379356148aa413eb684fbfff..0ae7ef47e7bf59b539c0ff52beab6aa33fd840a9 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/p2p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h index 35e8180d67ddcabc0ab1c639d1704386f592e606..98af94328abf9398283934b9db3a2ef0b87e1761 --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/sdspi.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/sdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Standard * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h index fc6e13b6cd489476539d58b0fc4030d7adcef5d1..643a73a76a4bd63114b8bb89b6742fe624482c0b --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/vlan.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h index 1a3ae0e8a6e1d3fb707b70f6e96ca29bd9e14d8f..147016f3730f4e007a0453d6250062fa85c72deb --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wpa.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wpa.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WPA * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h index e3d653ababe831a5a525410a7604b1351b146b23..aa3d19a382361e5f5dc3e4bec60c6050a01c4b7e --- a/drivers/net/wireless/bcmdhd_suzuran/include/proto/wps.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/proto/wps.h @@ -1,7 +1,7 @@ /* * WPS IE definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h index 00512bd0aa3a8bd8b2d964346c4c52ce4f35b882..51a07435bd5195a279388107e2c02812fda3d6df --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbchipc.h @@ -7,7 +7,7 @@ * * $Id: sbchipc.h 527121 2015-01-16 03:22:32Z $ * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h index 8de9b0942577a0d42d659faf5eda09146ecd3c02..569b0c9b731e08ae472cb4c2bcfa4af7a96a872e --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbconfig.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h index afe82680838fe0401e3c8361f0b9f2ea1ed40293..43ec49c47a3923163de6251c791c12fa0f5ff54c --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbhnddma.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbhnddma.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h index 20bb1748273b0e7c1a71198fde450b861f29b6a2..27d2f83f7c0a7cc824469d21edd7b208f4093f99 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbpcmcia.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h index 56e5f14fe34f437b405a3cd5a6786c779bfd0212..cca84bc18f28c3195506b5b7f4ce7bf28d5685e3 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdio.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdio.h @@ -4,7 +4,7 @@ * * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h index f24d0a3c4e76c7be030a62bd3d96c36ce08acedf..958436e3c45edc4e37e4bca0d7593ffe960f2742 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsdpcmdev.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsdpcmdev.h @@ -2,7 +2,7 @@ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific * device core support * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h index 1f4ab45b2e1c4e21dbbf683a12bde6d1076ffb2c..f9bfa969dc1bac7768faf87a9d4fef2216d42719 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sbsocram.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sdio.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h index 8b85c3593c826598a4d509484aea981af66b4f22..4b9573953bdf912a87e8d725c7d7e0f26b51749d --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdio.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdio.h @@ -2,7 +2,7 @@ * SDIO spec header file * Protocol and standard (common) device definitions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h index 62a5c4cc3179385e8fa68cd3bd7ea9f2bf92f648..754e01f6d6db27844ba2c580822d6a461ce8ceb8 --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdioh.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdioh.h @@ -2,7 +2,7 @@ * SDIO Host Controller Spec header file * Register map and definitions for the Standard Host Controller * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h b/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h index 326b32d8dfb0dc8654f811809d99ae1b951e51a5..734a17d6a34cb4a72fa3e111b857d9e702fca4ba --- a/drivers/net/wireless/bcmdhd_suzuran/include/sdiovar.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/sdiovar.h @@ -2,7 +2,7 @@ * Structure used by apps whose drivers access SDIO drivers. * Pulled out separately so dhdu and wlu can both use it. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h b/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/siutils.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h index 19a18ee50a996faafb7fc11632da72d3b3010a0f..5ea12f196284a09498572f577a09c37ad160b753 --- a/drivers/net/wireless/bcmdhd_suzuran/include/siutils.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/siutils.h @@ -2,7 +2,7 @@ * Misc utility routines for accessing the SOC Interconnects * of Broadcom HNBU chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/spid.h b/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/spid.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/spid.h index b5d7b675748d002bd1ce52b823e9bdfd9b4960fe..87d8291c1987016860d54246fa95bc01666fbb2b --- a/drivers/net/wireless/bcmdhd_suzuran/include/spid.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/spid.h @@ -1,7 +1,7 @@ /* * SPI device spec header file * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h b/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h index 5ea40e739e310195d4094a7c18692e11f3f54a18..3cd08f8e1686f7e2c3f89734025ebbc6a1ed9740 --- a/drivers/net/wireless/bcmdhd_suzuran/include/trxhdr.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h b/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h index 0222b8824c5f833c063ee72487e28951caf725f2..236b22862049064fded8bbbb2cc013bb2cb9fe28 --- a/drivers/net/wireless/bcmdhd_suzuran/include/typedefs.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h index 90624b6a5b48044785105931a78da6ae2e2aafe8..4355e72a3e2982d9f9db0b27a5b1d70103fcf955 --- a/drivers/net/wireless/bcmdhd_suzuran/include/wlfc_proto.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlfc_proto.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2017, Broadcom Corporation +* Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h rename to drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h index cec5d1eb56729653a6a90435009a614b86f278ee..226d38a2bcd844eb8ed721ae07f13c02229fe144 --- a/drivers/net/wireless/bcmdhd_suzuran/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/include/wlioctl.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c b/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/linux_osl.c rename to drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c index 0bd42de1f62bbe8db26aa93e4a8facd3c1b0a496..03d490dc8da21289569e2c59e5550e023a3ebf17 --- a/drivers/net/wireless/bcmdhd_suzuran/linux_osl.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/sbutils.c b/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/sbutils.c rename to drivers/net/wireless/bcmdhd_bcm43455/sbutils.c index c0364f6084661bb3053c5aca7e498c6a5844cb5c..a625d65993d332fff28644151fbd12138d7ba87a --- a/drivers/net/wireless/bcmdhd_suzuran/sbutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/sbutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils.c b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/siutils.c rename to drivers/net/wireless/bcmdhd_bcm43455/siutils.c index 822161a5fbe73fa45273f1db8d0b002d5122d248..bf91a266e74bb34510ab17c8eaa3a695b21bed3d --- a/drivers/net/wireless/bcmdhd_suzuran/siutils.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -401,12 +401,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } sih->bustype = bustype; +#ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } - +#endif /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); diff --git a/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h b/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h rename to drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h index e553ce355404b71d9baeaaa4ed44377ee0bae50c..1712409c7d70f25c6ad3c30edb0856d73df3d224 --- a/drivers/net/wireless/bcmdhd_suzuran/siutils_priv.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/siutils_priv.h @@ -1,7 +1,7 @@ /* * Include file private to the SOC Interconnect support files. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h b/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/uamp_api.h rename to drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h index 93d1d2eb208bbd3fedbdc441d03805a84cc3539e..01935148ee9ba1826ceb8cb9aa081b5af58aebc5 --- a/drivers/net/wireless/bcmdhd_suzuran/uamp_api.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/uamp_api.h @@ -3,7 +3,7 @@ * * Description: Universal AMP API * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/wl_android.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_android.c index 5924e82e83f8effc7a1ab8f5945b6aa37f0281a9..8c62fe4545b6798cecd0025f45e680b00087b069 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2015 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 701450 2017-05-25 02:10:23Z $ + * $Id: wl_android.c 736234 2017-12-14 04:22:25Z $ */ #include @@ -294,19 +294,22 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_ return -1; if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); - } else if (total_len <= ssid.SSID_len) { - return -ENOMEM; } else { - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; + if (total_len > ssid.SSID_len) { + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + } else { + return BCME_ERROR; + } } - if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) - return -ENOMEM; - - bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, + if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) { + bytes_written += snprintf(&command[bytes_written], total_len - bytes_written, " rssi %d", rssi); - command[bytes_written] = '\0'; + command[bytes_written] = '\0'; + } else { + return BCME_ERROR; + } DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); return bytes_written; @@ -378,7 +381,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) int err = BCME_OK; uint i, tokens; char *pos, *pos2, *token, *token2, *delim; - char param[PNO_PARAM_SIZE], value[VALUE_SIZE]; + char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; struct dhd_pno_batch_params batch_params; DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); if (total_len < strlen(CMD_WLS_BATCHING)) { @@ -1286,6 +1289,10 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); + if (num_ucipher_suites > MAX_NUM_SUITES) { + DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); + return -1; + } /* Increment for number of cipher suites field + space */ pcmd += 3; total_len_left -= 3; @@ -2015,13 +2022,18 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } } if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) { - DHD_ERROR(("%s: invalid length of private command : %d\n", + DHD_ERROR(("%s: invalid length of private command : %d \n", __FUNCTION__, priv_cmd.total_len)); ret = -EINVAL; goto exit; } - buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); + if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) { + buf_size = PRIVATE_COMMAND_DEF_LEN; + } else { + buf_size = priv_cmd.total_len; + } + command = kmalloc((buf_size + 1), GFP_KERNEL); if (!command) @@ -2263,19 +2275,22 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) #endif else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); - bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL"); + snprintf(command, 5, "FAIL"); + bytes_written = strlen("FAIL"); } if (bytes_written >= 0) { - if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { command[0] = '\0'; + } if (bytes_written >= priv_cmd.total_len) { - DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n", - __FUNCTION__, bytes_written, buf_size)); + DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n", + __FUNCTION__, bytes_written, priv_cmd.total_len)); ret = BCME_BUFTOOSHORT; goto exit; + } else { + bytes_written++; } - bytes_written++; priv_cmd.used_len = bytes_written; if (copy_to_user(priv_cmd.buf, command, bytes_written)) { DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); @@ -2288,7 +2303,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) exit: net_os_wake_unlock(net); - kfree(command); + if (command) { + kfree(command); + } return ret; } diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_android.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/wl_android.h rename to drivers/net/wireless/bcmdhd_bcm43455/wl_android.h index fb3cba9cf17bf4c134ce16ce32f6372735323a3e..1045e6ea2e3204eaf1577c23d2c72feaa326aba0 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_android.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_android.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c index 85d6aea376b9c81e12c539d6b2b27aa8d102adc8..3787c351d9089023a73b820eff6dd21097c2c435 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * Copyright (C) 2015 Sony Mobile Communications Inc. * * Unless you and Broadcom execute a separate written software license @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 718508 2017-08-31 02:48:38Z $ + * $Id: wl_cfg80211.c 751081 2018-03-09 08:06:41Z $ */ /* */ #include @@ -378,8 +378,9 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_del_station( + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -5593,7 +5594,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, WL_DBG(("Enter \n")); - if (len > ACTION_FRAME_SIZE) { + if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { WL_ERR(("bad length:%zu\n", len)); return BCME_BADLEN; } @@ -5634,7 +5635,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, s32 ie_len = len - ie_offset; if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -6796,9 +6797,8 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -6810,6 +6810,8 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; + const u8 *mac_addr = params->mac; + WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); @@ -8524,6 +8526,27 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -8534,45 +8557,34 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) } if (assoc_info.req_len) { err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + assoc_info.req_len, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); } if (assoc_info.resp_len) { err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + assoc_info.resp_len, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); + } + +exit: + if (err) { + WL_ERR(("err:%d, assoc_info-req:%u,resp:%u conn_info-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); return err; } @@ -9841,7 +9853,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, int max_wait_timeout = 2; int max_wait_count = 100; int refcnt = 0; - unsigned long limit = jiffies + max_wait_timeout * HZ; + unsigned long limit = jiffies + max_wait_timeout * msecs_to_jiffies(1000); while (work_pending(&wdev->cleanup_work)) { if (refcnt%5 == 0) { WL_ERR(("[NETDEV_DOWN] wait for " @@ -9863,7 +9875,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100); + (void)schedule_timeout(HZ); set_current_state(TASK_RUNNING); refcnt++; } @@ -10232,16 +10244,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); } -#ifdef GSCAN_SUPPORT - else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { - if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } -#else else if (status == WLC_E_STATUS_ABORT) { -#endif /* GSCAN_SUPPORT */ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; wl_escan_print_sync_id(status, escan_result->sync_id, cfg->escan_info.cur_sync_id); @@ -11211,6 +11214,13 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) #undef LOCAL_BUF_LEN list = (wl_uint32_list_t *)(void *)pbuf; + + if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { + WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); + kfree(pbuf); + return INVCHANSPEC; + } + band = array_size = n_2g = n_5g = 0; for (i = 0; i < dtoh32(list->count); i++) { index = 0; diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h index 069eda344e49e5b1b0b4b6a973962943e6d4d047..08a8c258e0f1117e0d48c1ffdabe76cec1e29054 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.h 596861 2015-11-03 08:54:58Z $ + * $Id: wl_cfg80211.h 751081 2018-03-09 08:06:41Z $ */ #ifndef _wl_cfg80211_h_ @@ -364,12 +364,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c index 9ed1748463ab21f6e2bc3582fd89c4761d994e33..eb02ffaf2b1c5649b3f00c12c08c36e726a02394 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfg_btcoex.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfg_btcoex.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c index 723211896d50f9083eae6148de40fd3dbbe15d03..974548ae33c3de0d47322166d353ba2630ca6199 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.c @@ -3,7 +3,7 @@ * * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h index 44484eba1d6829590fd2a00e3e9ff571df8f1b9e..bec3b72be0b0bc7898455cef98e8b9beb0c43e76 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgnan.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgnan.h @@ -3,7 +3,7 @@ * * Support NAN (Neighbor Awareness Networking) and RTT (Round Trip Time) * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c index f7b8c2b99ee53a994874c3cb9e481f1f6432dc53..d6c063f22656218fe9639f3b4d342a32e0584399 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.c @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h index cca3f7b339cb06a1fb8b2f302cd20d2398f2765d..40fa2a169708dd2c71793dc5d9f313e7a1b8bfc5 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgp2p.h @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c old mode 100755 new mode 100644 similarity index 96% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c index d1b5543b07e8e102088f47d90be8b3e98eac8e30..114c68d26db778aa74cbc452a9e1435ded09e102 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -213,6 +213,27 @@ wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy, return err; } +#ifdef CUSTOM_FORCE_NODFS_FLAG +static int +wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int err = 0; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + int type; + u32 nodfs; + + type = nla_type(data); + if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) { + nodfs = nla_get_u32(data); + err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs); + } else { + err = -1; + } + return err; +} +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + #ifdef GSCAN_SUPPORT int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, @@ -1278,53 +1299,88 @@ wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, int err = 0; int type, tmp; const struct nlattr *iter; - uint32 mem_needed = 0, flush = 0, i = 0, num = 0; + uint32 mem_needed = 0, flush = 0, num = 0; /* Assumption: NUM attribute must come first */ nla_for_each_attr(iter, data, len, tmp) { type = nla_type(iter); switch (type) { case GSCAN_ATTRIBUTE_NUM_BSSID: + if (num != 0) { + WL_ERR(("attempt to change BSSID num\n")); + err = -EINVAL; + goto exit; + } + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } num = nla_get_u32(iter); - if (num > MAX_BSSID_BLACKLIST_NUM) { - WL_ERR(("Too many Blacklist BSSIDs!\n")); + if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) { + WL_ERR(("wrong BSSID count:%d\n", num)); err = -EINVAL; goto exit; } + if (!blacklist) { + mem_needed = OFFSETOF(maclist_t, ea) + + sizeof(struct ether_addr) * (num); + blacklist = (maclist_t *) + kzalloc(mem_needed, GFP_KERNEL); + if (!blacklist) { + WL_ERR(("kzalloc failed.\n")); + err = -ENOMEM; + goto exit; + } + } break; case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH: + if (nla_len(iter) != sizeof(uint32)) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } flush = nla_get_u32(iter); + if (flush != 1) { + WL_ERR(("flush arg is worng:%d\n", flush)); + err = -EINVAL; + goto exit; + } break; case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: - if (num) { - if (!blacklist) { - mem_needed = sizeof(maclist_t) + - sizeof(struct ether_addr) * (num - 1); - blacklist = (maclist_t *) - kmalloc(mem_needed, GFP_KERNEL); - if (!blacklist) { - WL_ERR(("%s: Can't malloc %d bytes\n", - __FUNCTION__, mem_needed)); - err = -ENOMEM; - goto exit; - } - blacklist->count = num; - } - if (i >= num) { - WL_ERR(("CFGs don't seem right!\n")); - err = -EINVAL; - goto exit; - } - memcpy(&(blacklist->ea[i]), - nla_data(iter), ETHER_ADDR_LEN); - i++; + if (num == 0 || !blacklist) { + WL_ERR(("number of BSSIDs not received.\n")); + err = -EINVAL; + goto exit; } + if (nla_len(iter) != ETHER_ADDR_LEN) { + WL_ERR(("not matching nla_len.\n")); + err = -EINVAL; + goto exit; + } + if (blacklist->count >= num) { + WL_ERR(("too many BSSIDs than expected:%d\n", + blacklist->count)); + err = -EINVAL; + goto exit; + } + memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter), + ETHER_ADDR_LEN); + blacklist->count++; break; - default: - WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type)); - break; - } + default: + WL_ERR(("No such attribute:%d\n", type)); + break; + } } + + if (blacklist && (blacklist->count != num)) { + WL_ERR(("not matching bssid count:%d to expected:%d\n", + blacklist->count, num)); + err = -EINVAL; + goto exit; + } + err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), blacklist, mem_needed, flush); exit: @@ -1852,36 +1908,6 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de } #endif /* defined(KEEP_ALIVE) */ -static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int len) -{ - struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - int err = 0; - int data_len = 0; - - WL_INFO(("%s: Enter \n", __func__)); - - if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) { - err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - data_len = strlen(cfg->ioctl_buf); - cfg->ioctl_buf[data_len] = '\0'; - } - - err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg), - cfg->ioctl_buf, data_len+1); - if (unlikely(err)) - WL_ERR(("Vendor Command reply failed ret:%d \n", err)); - else - WL_INFO(("Vendor Command reply sent successfully!\n")); - - return err; -} - #ifdef LINKSTAT_SUPPORT #define NUM_RATE 32 #define NUM_PEER 1 @@ -2074,14 +2100,6 @@ static int wl_cfgvendor_set_country(struct wiphy *wiphy, } static const struct wiphy_vendor_command wl_vendor_cmds [] = { - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_PRIV_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_priv_string_handler - }, #ifdef GSCAN_SUPPORT { { @@ -2198,6 +2216,17 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = { .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_set_rand_mac_oui }, +#ifdef CUSTOM_FORCE_NODFS_FLAG + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_NODFS_CHANNELS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_nodfs_flag + + }, +#endif /* CUSTOM_FORCE_NODFS_FLAG */ #ifdef LINKSTAT_SUPPORT { { diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h rename to drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h index a352a9b1415dfc2764d5d496b18b34ec93fd3021..2212ec3beae9c0092668e23b6c18f1c613a1bf0b --- a/drivers/net/wireless/bcmdhd_suzuran/wl_cfgvendor.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_cfgvendor.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 Vendor Extension Code * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -341,9 +341,6 @@ enum mkeep_alive_attributes { MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC }; -/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ -#define BRCM_VENDOR_SCMD_CAPA "cap" - #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) extern int wl_cfgvendor_attach(struct wiphy *wiphy); extern int wl_cfgvendor_detach(struct wiphy *wiphy); diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h b/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h rename to drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h index 02d653e4e1d63afda33d0ba7f5218a493a8a030d..e41c479a083592e5241f775993b90557a4c9683d --- a/drivers/net/wireless/bcmdhd_suzuran/wl_dbg.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_dbg.h @@ -2,7 +2,7 @@ * Minimal debug/trace/assert driver definitions for * Broadcom 802.11 Networking Adapter. * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c index a15c132b7dffad07d97cf6d1b7cd45b1f8fccdc1..271dfc250a0313340004b9080d09ac614507ed6d --- a/drivers/net/wireless/bcmdhd_suzuran/wl_linux_mon.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_linux_mon.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), Linux monitor network interface * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c b/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/wl_roam.c rename to drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c index 957640888266a5368b377b84d1b2fe9d25431096..50180753ad775ec95bc605a95f1bccecb94c4919 --- a/drivers/net/wireless/bcmdhd_suzuran/wl_roam.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wl_roam.c @@ -1,7 +1,7 @@ /* * Linux roam cache * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c old mode 100755 new mode 100644 similarity index 97% rename from drivers/net/wireless/bcmdhd_suzuran/wldev_common.c rename to drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c index 08a5ecaf6560aea9e041a1c045a601ae0ca603cf..decaf3560d42624cb6cf1b7779a75e8b8b220593 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.c @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,6 +31,7 @@ #include #include +#include #define htod32(i) (i) #define htod16(i) (i) @@ -369,6 +370,9 @@ int wldev_set_country( wl_country_t cspec = {{0}, 0, {0}}; scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; + struct wireless_dev *wdev = ndev_to_wdev(dev); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (!country_code) return error; @@ -383,7 +387,7 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - if (user_enforced) { + if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); if (error < 0) { diff --git a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h old mode 100755 new mode 100644 similarity index 98% rename from drivers/net/wireless/bcmdhd_suzuran/wldev_common.h rename to drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h index d1746dd0d9cc811239a96485179931ce513b1ffc..07f3d56b4cb2b80bbc98e696f1ccdf9254a819f8 --- a/drivers/net/wireless/bcmdhd_suzuran/wldev_common.h +++ b/drivers/net/wireless/bcmdhd_bcm43455/wldev_common.h @@ -1,7 +1,7 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2017, Broadcom Corporation + * Copyright (C) 1999-2018, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig similarity index 78% rename from drivers/net/wireless/bcmdhd/Kconfig rename to drivers/net/wireless/bcmdhd_bcm4356/Kconfig index c35b821553b61a01723362743637b0c36b99401a..a89ca15ef8f0082ad95ef706d8d0447cbce656de 100644 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ b/drivers/net/wireless/bcmdhd_bcm4356/Kconfig @@ -1,9 +1,15 @@ +menuconfig BCMDHD_BCM4356 + tristate "Broadcom wireless cards support" + +if BCMDHD_BCM4356 + config BCMDHD tristate "Broadcom wireless cards support" depends on MMC || PCI ---help--- This module adds support for wireless adapters based on Broadcom chipset. + config BCMDHD_SDIO bool "SDIO bus interface support" depends on BCMDHD && MMC && !BCMDHD_PCIE @@ -19,12 +25,12 @@ config BCM4339 This module adds support for wireless adapters based on Broadcom 4339 chipset. -config BCM4354 - bool "Broadcom 4354 wireless cards support" - depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) - ---help--- - This module adds support for wireless adapters based on - Broadcom 4354 chipset. +#config BCM4354 +# bool "Broadcom 4354 wireless cards support" +# depends on BCMDHD && (BCMDHD_SDIO || BCMDHD_PCIE) +# ---help--- +# This module adds support for wireless adapters based on +# Broadcom 4354 chipset. config BCM4356 bool "Broadcom 4356 wireless cards support" @@ -36,14 +42,14 @@ config BCM4356 config BCMDHD_FW_PATH depends on BCMDHD string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" + default "/system/etc/firmware/wlan/bcmdhd/fw_bcmdhd.bin" ---help--- Path to the firmware file. config BCMDHD_NVRAM_PATH depends on BCMDHD string "NVRAM path" - default "/system/etc/wifi/bcmdhd.cal" + default "/system/etc/firmware/wlan/bcmdhd/bcmdhd.cal" ---help--- Path to the calibration file. @@ -66,9 +72,11 @@ config BROADCOM_WIFI_RESERVED_MEM depends on BCMDHD ---help--- This is a configuration for broadcom WLAN driver. + config BCMDHD_DEBUG_PAGEALLOC bool "Enable Memory Pagealloc Debugging Support" depends on (BCM4354 || BCM4356) ---help--- Enable Memory Pagealloc Debugging +endif diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd_bcm4356/Makefile similarity index 97% rename from drivers/net/wireless/bcmdhd/Makefile rename to drivers/net/wireless/bcmdhd_bcm4356/Makefile index cfde5d2da84656194b77c3f171c82a7390f4044d..e19b954080a03c92acbdfcfb941c73d7bd3759db 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd_bcm4356/Makefile @@ -92,9 +92,6 @@ DHDCFLAGS += -DROAM_ENABLE DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND - - - # SoftAP DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP DHDCFLAGS += -DDISABLE_11H_SOFTAP @@ -211,8 +208,6 @@ DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT ANDROID_OFILES := wl_cfgvendor.o - - ########################## # driver type # m: module type driver @@ -293,7 +288,7 @@ endif DHDCFLAGS += -DDISABLE_TXBFR ifeq ($(CONFIG_BCM4356),y) DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -# DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC endif ifeq ($(BUS_IFACE_SDIO),y) DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 @@ -340,8 +335,6 @@ ifeq ($(BUS_IFACE_PCIE),y) DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE endif - - # New Features DHDCFLAGS += -DWL11U DHDCFLAGS += -DBCMCCX @@ -354,7 +347,7 @@ endif DHDCFLAGS += -DSUPPORT_WL_TXPOWER ifeq ($(CONFIG_BCM4354),y) DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -# DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC endif ifeq ($(BUS_IFACE_SDIO),y) @@ -405,6 +398,7 @@ endif DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP endif endif + ############################# # Platform dependent feature ############################# @@ -447,6 +441,11 @@ ifneq ($(CONFIG_SOMC_WLAN_LOW_POWER_NV_PATH),) endif endif +# Disable to delay link down event +#ifeq ($(CONFIG_SOMC_WLAN_DISABLE_BCM_DLY),y) +# DHDCFLAGS += -DDISABLE_BCN_DLY +#endif + # Change scan time ifeq ($(CONFIG_SOMC_CFG_WLAN_CHANGE_SCAN_TIME),y) DHDCFLAGS += -DCHANGE_SCAN_TIME @@ -461,18 +460,24 @@ endif ifneq ($(CONFIG_SOMC_WLAN_NVRAM_PATH),) DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH=\"$(CONFIG_SOMC_WLAN_NVRAM_PATH)\" endif + +# Enable Disconnection timing log +ifeq ($(CONFIG_SOMC_WLAN_ENABLE_DISC_TIME_LOG),y) + DHDCFLAGS += -DDHD_ENABLE_DISC_TIME_LOG +endif + + ######### # Others ######### - EXTRA_LDFLAGS += --strip-debug EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) -MODNAME := bcmdhd +MODNAME := wlan DHDOFILES := dhd_pno.o \ dhd_common.o \ @@ -527,6 +532,6 @@ endif DHDOFILES += $(ANDROID_OFILES) # Module information used by KBuild framework -obj-$(CONFIG_BCMDHD) += $(MODNAME).o +obj-$(CONFIG_BCMDHD_BCM4356) += $(MODNAME).o $(MODNAME)-objs := $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm new file mode 100644 index 0000000000000000000000000000000000000000..2bfbf9a59a8e1d100416ad4e7545098468064a0c --- /dev/null +++ b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.bcm @@ -0,0 +1,448 @@ +# bcmdhd +##################### +# Basic feature +##################### + +DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \ + -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ + -DDHDTHREAD -DDHD_BCMEVENTS -DSHOW_EVENTS -DBCMDBG -DWLP2P \ + -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ + -DPKT_FILTER_SUPPORT -DEMBEDDED_PLATFORM -DPNO_SUPPORT + +##################### +# Bus Interface Type +##################### +ifneq ($(CONFIG_BCMDHD_PCIE),) + BUS_IFACE_PCIE=y +else + BUS_IFACE_SDIO=y +endif + +##################### +# SDIO I/F +##################### +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT + DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR + DHDCFLAGS += -U__ARM_ARCH_7A__ + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=98 + # idle count + DHDCFLAGS += -DDHD_USE_IDLECOUNT + # SKB TAILPAD to avoid out of boundary memory access + DHDCFLAGS += -DDHDENABLE_TAILPAD + DHDCFLAGS += -DSUPPORT_P2P_GO_PS +endif + +##################### +# PCIE I/F +##################### +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE + # DPC priority + DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=-1 + # Enable Link down recovery + DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY + # Enable Firmware Coredump + DHDCFLAGS += -DDHD_FW_COREDUMP + + # Enable packet audit at host side + DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED +endif + + + +################# +# Common feature +################# + +DHDCFLAGS += -DCUSTOMER_HW2 -DCUSTOMER_HW5 +DHDCFLAGS += -DWL_CFG80211 + + +# Debug +DHDCFLAGS += -DSIMPLE_MAC_PRINT +DHDCFLAGS += -DDEBUGFS_CFG80211 +# Enable wakelock debug function +DHDCFLAGS += -DDHD_TRACE_WAKE_LOCK +# Print out kernel panic point of file and line info when assertion happened +DHDCFLAGS += -DBCMASSERT_LOG + +# Print 8021X +DHDCFLAGS += -DDHD_8021X_DUMP + +# VSDB +DHDCFLAGS += -DVSDB +DHDCFLAGS += -DPROP_TXSTATUS + +# Wi-Fi Direct +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +# For p2p connection issue +DHDCFLAGS += -DWL_SCB_TIMEOUT=10 +# For TDLS tear down inactive time 10 sec +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000 +# for TDLS RSSI HIGH for establishing TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80 +# for TDLS RSSI HIGH for tearing down TDLS link +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 + +# Roaming +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DROAM_ENABLE +DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND + + + + + +# SoftAP +DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DSUPPORT_HIDDEN_AP +DHDCFLAGS += -DDISABLE_11H_SOFTAP +DHDCFLAGS += -DSUPPORT_HOSTAPD_BGN_MODE +DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +# For setting custom short & long retry limit +DHDCFLAGS += -DSET_RETRY_LIMIT -DCUSTOM_SRL_SETTING=13 -DCUSTOM_LRL_SETTING=13 + +# HW5 specific features +DHDCFLAGS += -DSUPPORT_PM2_ONLY +DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD +DHDCFLAGS += -DBLOCK_IPV6_PACKET -DPASS_IPV4_SUSPEND + +# Support MAC ACL setting +DHDCFLAGS += -DWL_CFG80211_ACL +# Connection statistics +DHDCFLAGS += -DCONNECTION_STATISTICS +# END HW5 specific features + + +# For special PNO Event keep wake lock for 10sec +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 +# For Passing all multicast packets to host when not in suspend mode. +DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + + +# Early suspend +DHDCFLAGS += -DDHD_USE_EARLYSUSPEND + +# WiFi turn off delay +DHDCFLAGS += -DWIFI_TURNOFF_DELAY=100 + +# For Scan result patch +DHDCFLAGS += -DESCAN_RESULT_PATCH +DHDCFLAGS += -DDUAL_ESCAN_RESULT_BUFFER +DHDCFLAGS += -DESCAN_BUF_OVERFLOW_MGMT + +# For Static Buffer +ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) + DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF + DHDCFLAGS += -DENHANCED_STATIC_BUF + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF +endif +ifeq ($(CONFIG_BCMDHD_DEBUG_PAGEALLOC),y) +# Preallocation for memory dump + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP +endif +endif + +# DTIM listen interval in suspend mode(0 means follow AP's DTIM period) +DHDCFLAGS += -DCUSTOM_SUSPEND_BCN_LI_DTIM=3 + +# Ioctl timeout 5000ms +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 + +# Ioctl Rx count timeout +DHDCFLAGS += -DMAX_CNTL_RX_TIMEOUT=3 + +# Priority mismatch fix with kernel stack +DHDCFLAGS += -DPKTPRIO_OVERRIDE + +# Prevent rx thread monopolize +DHDCFLAGS += -DWAIT_DEQUEUE + +# Config PM Control +DHDCFLAGS += -DCONFIG_CONTROL_PM + +# Use Android wake lock mechanism +DHDCFLAGS += -DCONFIG_HAS_WAKELOCK + +# Used short dwell time during initial scan +DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME + +#DHDCFLAGS += -DWL_ABORT_SCAN + +############################## +# Android Platform Definition +############################## + +########### +# Lollipop +########### +DHDCFLAGS += -DWL_ENABLE_P2P_IF +#DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES +# Default definitions for KitKat +DHDCFLAGS += -DWL_CFG80211_STA_EVENT +DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + +ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) +DHDCFLAGS += -DWL_SCHED_SCAN +endif + +# To support RTT +#DHDCFLAGS += -DRTT_SUPPORT +# To support Link Statictics +DHDCFLAGS += -DLINKSTAT_SUPPORT +# To support GSCAN +DHDCFLAGS += -DGSCAN_SUPPORT + +# To support WL_VENDOR_EXT_SUPPORT +DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT + +# Extra file list for Lollipop +ANDROID_OFILES := wl_cfgvendor.o + + + + +########################## +# driver type +# m: module type driver +# y: built-in type driver +########################## +DRIVER_TYPE ?= m + +######################### +# Chip dependent feature +######################### + +# Chipsets supported both SDIO and PCIE +ifneq ($(CONFIG_BCM4356),) + DHDCFLAGS += -DBCM4356_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB + DHDCFLAGS += -DDISABLE_PM_BCNRX + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +# DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=4 +# DHDCFLAGS += -DSET_PCIEIRQ_CPU0 +endif + + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE + DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=125 + DHDCFLAGS += -DDHD_USE_IDLECOUNT -DMAX_IDLE_COUNT=16 -DMAX_RESUME_WAIT=500 +endif + +ifeq ($(CONFIG_ARCH_MSM),y) + #DHDCFLAGS += -DSET_RPS_CPUS +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_DISABLE_ASYNC_SUSPEND +endif +endif + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +# DHDCFLAGS += -DDISABLE_IF_COUNTERS + DHDCFLAGS += -DDISABLE_TXBFR + +ifeq ($(CONFIG_BCM4356),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +ifneq ($(CONFIG_BCM4354),) + DHDCFLAGS += -DBCM4354_CHIP + DHDCFLAGS += -DMIMO_ANT_SETTING + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + +# tput enhancement for common + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DPROP_TXSTATUS_VSDB + +# tput enhancement for SDIO +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DHW_OOB + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=40 -DDHD_TXBOUND=40 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40 + DHDCFLAGS += -DMAX_HDR_READ=128 + DHDCFLAGS += -DDHD_FIRSTREAD=128 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16 + DHDCFLAGS += -DDHDTCPACK_SUPPRESS +endif + +# tput enhancement for PCIE +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=32 + DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=16 +endif + +ifeq ($(BUS_IFACE_PCIE),y) + DHDCFLAGS += -DBCMPCIE_OOB_HOST_WAKE +endif + + + +# New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC +# DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4354),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + +ifeq ($(BUS_IFACE_SDIO),y) + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 +endif +endif + +# Chipsets supported SDIO only +ifeq ($(BUS_IFACE_SDIO),y) +ifneq ($(CONFIG_BCM4339),) + DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB + DHDCFLAGS += -DUSE_CID_CHECK + DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP + DHDCFLAGS += -DUSE_SDIOFIFO_IOVAR + + # tput enhancement + DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1 + DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128 + DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED + DHDCFLAGS += -DDHDTCPACK_SUPPRESS + DHDCFLAGS += -DUSE_WL_TXBF + DHDCFLAGS += -DUSE_WL_FRAMEBURST + DHDCFLAGS += -DRXFRAME_THREAD + DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64 -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16 + DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +ifeq ($(CONFIG_ARCH_MSM),y) + DHDCFLAGS += -DCUSTOM_DEF_TXGLOM_SIZE=32 -DDHD_TXBOUND=32 + DHDCFLAGS += -DENABLE_ADAPTIVE_SCHED -DCUSTOM_CPUFREQ_THRESH=1000000 +endif + DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 + DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=3 + + # New Features + DHDCFLAGS += -DWL11U + DHDCFLAGS += -DBCMCCX + DHDCFLAGS += -DWLTDLS + DHDCFLAGS += -DWLFBT + DHDCFLAGS += -DDHD_ENABLE_LPC + DHDCFLAGS += -DSUPPORT_LTECX +# DHDCFLAGS += -DSUPPORT_2G_VHT + DHDCFLAGS += -DSUPPORT_WL_TXPOWER +ifeq ($(CONFIG_BCM4339),y) + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC +endif + DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30 + DHDCFLAGS += -DDISABLE_WL_FRAMEBURST_SOFTAP +endif +endif +############################# +# Platform dependent feature +############################# +######### +# Others +######### + + +EXTRA_LDFLAGS += --strip-debug +EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG +EXTRA_CFLAGS += -DSRCBASE=\"$(src)\" +EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/ +KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) + +DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \ + dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \ + bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \ + wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o \ + wl_linux_mon.o wl_roam.o dhd_linux_platdev.o dhd_linux_wq.o wl_cfg_btcoex.o \ + dhd_wlfc.o hnd_pktq.o hnd_pktpool.o wl_cfgnan.o bcmxtlv.o + + +ifeq ($(BUS_IFACE_SDIO),y) +DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o +DHDOFILES += dhd_cdc.o dhd_sdio.o +endif + + +ifeq ($(BUS_IFACE_PCIE),y) +DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o dhd_msgbuf.o +endif + + +DHDOFILES += $(ANDROID_OFILES) + +bcmdhd-objs := $(DHDOFILES) +obj-$(DRIVER_TYPE) += bcmdhd.o + +all: + @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules" + @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules + +clean: + rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \ + Module.symvers modules.order .tmp_versions modules.builtin + +install: + @$(MAKE) --no-print-directory -C $(KDIR) \ + SUBDIRS=$(CURDIR) modules_install diff --git a/drivers/net/wireless/bcmdhd/Makefile.kk b/drivers/net/wireless/bcmdhd_bcm4356/Makefile.kk similarity index 100% rename from drivers/net/wireless/bcmdhd/Makefile.kk rename to drivers/net/wireless/bcmdhd_bcm4356/Makefile.kk diff --git a/drivers/net/wireless/bcmdhd/Makefile_Shamu b/drivers/net/wireless/bcmdhd_bcm4356/Makefile_Shamu similarity index 100% rename from drivers/net/wireless/bcmdhd/Makefile_Shamu rename to drivers/net/wireless/bcmdhd_bcm4356/Makefile_Shamu diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd_bcm4356/aiutils.c similarity index 100% rename from drivers/net/wireless/bcmdhd/aiutils.c rename to drivers/net/wireless/bcmdhd_bcm4356/aiutils.c diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c similarity index 92% rename from drivers/net/wireless/bcmdhd/bcmevent.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c index 09c5698910412db44b9caab5b4f306206b0452d1..58fa662e840b64ad10d029093979ca6532bb0363 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmevent.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c 642286 2016-06-08 05:57:20Z $ + * $Id: bcmevent.c 718504 2017-08-31 02:38:08Z $ */ #include @@ -212,14 +212,14 @@ int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, void *out_event) { - uint16 evlen; + uint16 evlen = 0; /* length in bcmeth_hdr */ uint16 subtype; uint16 usr_subtype; bcm_event_t *bcm_event; uint8 *pktend; uint8 *evend; int err = BCME_OK; - uint32 data_len; + uint32 data_len = 0; /* data length in bcm_event */ pktend = (uint8 *)pktdata + pktlen; bcm_event = (bcm_event_t *)pktdata; @@ -240,9 +240,13 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, } /* check length in bcmeth_hdr */ - evlen = ntoh16_ua((void *)&bcm_event->bcm_hdr.length); + /* temporary - header length not always set properly. When the below + * !BCMDONGLEHOST is in all branches that use trunk DHD, the code + * under BCMDONGLEHOST can be removed. + */ + evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version); evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; - if (evend != pktend) { + if (evend > pktend) { err = BCME_BADLEN; goto done; } @@ -263,15 +267,16 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); switch (usr_subtype) { case BCMILCP_BCM_SUBTYPE_EVENT: + /* check that header length and pkt length are sufficient */ if ((pktlen < sizeof(bcm_event_t)) || - (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { + (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { err = BCME_BADLEN; goto done; } + /* ensure data length in event is not beyond the packet. */ data_len = ntoh32_ua((void *)&bcm_event->event.datalen); - if ((sizeof(bcm_event_t) + data_len + - BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) { + if (data_len > (pktlen - sizeof(bcm_event_t))) { err = BCME_BADLEN; goto done; } @@ -292,6 +297,7 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, goto done; } + BCM_REFERENCE(data_len); done: return err; } diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmsdh.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmsdh.c diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_linux.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmsdh_linux.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_linux.c diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc.c diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmsdh_sdmmc_linux.c diff --git a/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmsdspi_linux.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmsdspi_linux.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmsdspi_linux.c diff --git a/drivers/net/wireless/bcmdhd/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmspibrcm.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmspibrcm.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmspibrcm.c diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c similarity index 99% rename from drivers/net/wireless/bcmdhd/bcmutils.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c index d110b6f062deba672790e3b6e90b38bc2ec3c2e6..d37ada4e7495a6bf863aa3145945ad451c2656f7 100644 --- a/drivers/net/wireless/bcmdhd/bcmutils.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/bcmutils.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmutils.c 617200 2016-02-04 12:23:42Z $ + * $Id: bcmutils.c 701287 2017-05-24 10:33:19Z $ */ #include @@ -1707,8 +1707,10 @@ bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) strncpy(buf, name, buflen); /* append data onto the end of the name string */ - memcpy(&buf[len], data, datalen); - len += datalen; + if (data && datalen != 0) { + memcpy(&buf[len], data, datalen); + len += datalen; + } return len; } diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmwifi_channels.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.c diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.h similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmwifi_channels.h rename to drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_channels.h diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_rates.h similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmwifi_rates.h rename to drivers/net/wireless/bcmdhd_bcm4356/bcmwifi_rates.h diff --git a/drivers/net/wireless/bcmdhd/bcmxtlv.c b/drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c similarity index 100% rename from drivers/net/wireless/bcmdhd/bcmxtlv.c rename to drivers/net/wireless/bcmdhd_bcm4356/bcmxtlv.c diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd.h similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd.h index 14ee1ad2ac8b2e66a0f3e51f0a9c67edf5a6c486..f77554c2c43f1443047f3e6308d6b569fb08bddb 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd.h @@ -25,7 +25,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h 676009 2016-12-20 02:54:41Z $ + * $Id: dhd.h 701287 2017-05-24 10:33:19Z $ */ /**************** @@ -990,7 +990,8 @@ extern int dhd_os_d3ack_wait(dhd_pub_t * pub, uint * condition, bool * pending); extern int dhd_os_d3ack_wake(dhd_pub_t * pub); extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); -extern int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set); +int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, + char *res_buf, uint res_len, int set); extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, char **resptr, uint resp_len); typedef enum cust_gpio_modes { diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c index 62b78e61d30907642c0087607876fdc87568fd14..c830b3cf5d873523ea11942159f5ce15817b309a --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_bta.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_bta.c 701450 2017-05-25 02:10:23Z $ + * $Id: dhd_bta.c 701287 2017-05-24 10:33:19Z $ */ #error "WLBTAMP is not defined" diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_bta.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_bta.h diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_bus.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_bus.h diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_cdc.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_cdc.c diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c similarity index 97% rename from drivers/net/wireless/bcmdhd/dhd_cfg80211.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c index 4dd551754756e5c021c9f78354c725a704459a41..db75a2e36b5ed01d1163fabd0a12248b734b83b0 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.c @@ -168,7 +168,7 @@ wl_dongle_up(struct net_device *ndev) s32 err = 0; u32 up = 0; - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); + err = wldev_ioctl_set(ndev, WLC_UP, &up, sizeof(up)); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); } @@ -181,7 +181,7 @@ wl_dongle_down(struct net_device *ndev) s32 err = 0; u32 down = 0; - err = wldev_ioctl(ndev, WLC_DOWN, &down, sizeof(down), true); + err = wldev_ioctl_set(ndev, WLC_DOWN, &down, sizeof(down)); if (unlikely(err)) { WL_ERR(("WLC_DOWN error (%d)\n", err)); } diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_cfg80211.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg80211.h diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_cfg_vendor.c diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c similarity index 93% rename from drivers/net/wireless/bcmdhd/dhd_common.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c index feafd315824d67455152acf5e1df5d8db7cbbfcd..0cf348324f65a1ba2a8de058cc5a407408027097 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 642286 2016-06-08 05:57:20Z $ + * $Id: dhd_common.c 701287 2017-05-24 10:33:19Z $ */ #include #include @@ -83,6 +83,10 @@ extern void htsf_update(struct dhd_info *dhd, void *data); int dhd_msg_level = DHD_ERROR_VAL; +#if defined(WL_WIRELESS_EXT) +#include +#endif + #ifdef SOFTAP char fw_path2[MOD_PARAM_PATHLEN]; extern bool softap_enabled; @@ -111,7 +115,7 @@ bool ap_fw_loaded = FALSE; /* Version string to report */ #ifdef DHD_DEBUG #ifndef SRCBASE -#define SRCBASE "drivers/net/wireless/bcmdhd" +#define SRCBASE "drivers/net/wireless/bcmdhd_bcm4356" #endif #define DHD_COMPILED "\nCompiled in " SRCBASE #endif /* DHD_DEBUG */ @@ -1645,7 +1649,7 @@ wl_host_event_get_data(void *pktdata, uint pktlen, void *evt) int ret; ret = is_wlc_event_frame(pktdata, pktlen, 0, evt); - if (ret != BCME_OK) { + if (ret != BCME_OK && ret != -30) { DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret)); } @@ -1991,8 +1995,8 @@ dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_ __FUNCTION__, arg)); /* Contorl the master mode */ - bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + rc = dhd_iovar(dhd, 0, "pkt_filter_mode", (char *)&master_mode, + sizeof(master_mode), NULL, 0, TRUE); rc = rc >= 0 ? 0 : rc; if (rc) DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", @@ -2142,11 +2146,10 @@ fail: void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) { - char iovbuf[32]; int ret; - bcm_mkiovar("pkt_filter_delete", (char *)&id, 4, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + ret = dhd_iovar(dhd, 0, "pkt_filter_delete", (char *)&id, + sizeof(id), NULL, 0, TRUE); if (ret < 0) { DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", __FUNCTION__, id, ret)); @@ -2161,18 +2164,10 @@ void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) { - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iovar_len; int retcode; - iovar_len = bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); - if (!iovar_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0); + retcode = dhd_iovar(dhd, 0, "arp_ol", (char *)&arp_mode, + sizeof(arp_mode), NULL, 0, TRUE); retcode = retcode >= 0 ? 0 : retcode; if (retcode) DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", @@ -2186,17 +2181,10 @@ void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) { char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iovar_len; int retcode; - iovar_len = bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); - if (!iovar_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0); + retcode = dhd_iovar(dhd, 0, "arpoe", (char *)&arp_enable, + sizeof(arp_enable), NULL, 0, TRUE); retcode = retcode >= 0 ? 0 : retcode; if (retcode) DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", @@ -2206,8 +2194,9 @@ dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) __FUNCTION__, arp_enable)); if (arp_enable) { uint32 version; - bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf)); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); + memset(iovbuf, 0, sizeof(iovbuf)); + retcode = dhd_iovar(dhd, 0, "arp_version", NULL, 0, iovbuf, sizeof(iovbuf), + FALSE); if (retcode) { DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n", __FUNCTION__, retcode)); @@ -2225,20 +2214,13 @@ void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) { int ret = 0; - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; if (dhd == NULL) return; if (dhd->arp_version == 1) idx = 0; - iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) + ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); } @@ -2246,46 +2228,29 @@ void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) { int ret = 0; - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; if (dhd == NULL) return; if (dhd->arp_version == 1) idx = 0; - iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) + ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); } void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) { - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int retcode; - + int ret; if (dhd == NULL) return; if (dhd->arp_version == 1) idx = 0; - iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, - sizeof(ipaddr), iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - if (retcode) - DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", - __FUNCTION__, retcode)); + ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr), + NULL, 0, TRUE); + if (ret) + DHD_TRACE(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret)); else DHD_TRACE(("%s: sARP H ipaddr entry added \n", __FUNCTION__)); @@ -2294,8 +2259,7 @@ dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) { - int retcode, i; - int iov_len; + int ret, i; uint32 *ptr32 = buf; bool clr_bottom = FALSE; @@ -2305,13 +2269,11 @@ dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) if (dhd->arp_version == 1) idx = 0; - iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); - BCM_REFERENCE(iov_len); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx); - - if (retcode) { + ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, + FALSE); + if (ret) { DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", - __FUNCTION__, retcode)); + __FUNCTION__, ret)); return -1; } @@ -2338,20 +2300,13 @@ dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) { - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iov_len; int retcode; if (dhd == NULL) return -1; - iov_len = bcm_mkiovar("ndoe", (char *)&ndo_enable, 4, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); + retcode = dhd_iovar(dhd, 0, "ndoe", (char *)&ndo_enable, + sizeof(ndo_enable), NULL, 0, TRUE); if (retcode) DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n", __FUNCTION__, ndo_enable, retcode)); @@ -2369,21 +2324,13 @@ dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) { - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; int retcode; if (dhd == NULL) return -1; - iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr, - IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); + retcode = dhd_iovar(dhd, idx, "nd_hostip", ipv6addr, + IPV6_ADDR_LEN, NULL, 0, TRUE); if (retcode) DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n", @@ -2401,21 +2348,13 @@ dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) { - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE]; int retcode; if (dhd == NULL) return -1; - iov_len = bcm_mkiovar("nd_hostip_clear", NULL, - 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); + retcode = dhd_iovar(dhd, idx, "nd_hostip_clear", NULL, 0, + NULL, 0, TRUE); if (retcode) DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", @@ -2596,6 +2535,79 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) return res; } #endif /* defined(KEEP_ALIVE) */ +#define CSCAN_TLV_TYPE_SSID_IE 'S' +/* + * SSIDs list parsing from cscan tlv list + */ +int +wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) +{ + char* str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + str = *list_str; + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + *list_str = str; + DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + + /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + *bytes_left -= 1; + str += 1; + ssid[idx].rssi_thresh = 0; + if (str[0] == 0) { + /* Broadcast SSID */ + ssid[idx].SSID_len = 0; + memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); + *bytes_left -= 1; + str += 1; + + DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); + } + else if (str[0] <= DOT11_MAX_SSID_LEN) { + /* Get proper SSID size */ + ssid[idx].SSID_len = str[0]; + *bytes_left -= 1; + str += 1; + + /* Get SSID */ + if (ssid[idx].SSID_len > *bytes_left) { + DHD_ERROR(("%s out of memory range len=%d but left=%d\n", + __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); + return -1; + } + + memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); + + *bytes_left -= ssid[idx].SSID_len; + str += ssid[idx].SSID_len; + ssid[idx].hidden = TRUE; + + DHD_TRACE(("%s :size=%d left=%d\n", + (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } + else { + DHD_ERROR(("### SSID size more that %d\n", str[0])); + return -1; + } + + if (idx++ > max) { + DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); + return -1; + } + } + + *list_str = str; + return idx; +} +#if defined(WL_WIRELESS_EXT) /* Android ComboSCAN support */ /* @@ -2648,76 +2660,133 @@ wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, return 1; } -#define CSCAN_TLV_TYPE_SSID_IE 'S' - /* - * SSIDs list parsing from cscan tlv list - */ + * channel list parsing from cscan tlv list +*/ int -wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) +wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, + int channel_num, int *bytes_left) { char* str; int idx = 0; - if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); return -1; } str = *list_str; + while (*bytes_left > 0) { - if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { *list_str = str; - DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); return idx; } - - /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ *bytes_left -= 1; str += 1; - ssid[idx].rssi_thresh = 0; + if (str[0] == 0) { - /* Broadcast SSID */ - ssid[idx].SSID_len = 0; - memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); - *bytes_left -= 1; - str += 1; + /* All channels */ + channel_list[idx] = 0x0; + } + else { + channel_list[idx] = (uint16)str[0]; + DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); + } + *bytes_left -= 1; + str += 1; - DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); + if (idx++ > 255) { + DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); + return -1; } - else if (str[0] <= DOT11_MAX_SSID_LEN) { - /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; - *bytes_left -= 1; - str += 1; + } - /* Get SSID */ - if (ssid[idx].SSID_len > *bytes_left) { - DHD_ERROR(("%s out of memory range len=%d but left=%d\n", - __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; - } + *list_str = str; + return idx; +} - memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); +/* Parse a comma-separated list from list_str into ssid array, starting + * at index idx. Max specifies size of the ssid array. Parses ssids + * and returns updated idx; if idx >= max not all fit, the excess have + * not been copied. Returns -1 on empty string, or on ssid too long. + */ +int +wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) +{ + char* str, *ptr; - *bytes_left -= ssid[idx].SSID_len; - str += ssid[idx].SSID_len; - ssid[idx].hidden = TRUE; + if ((list_str == NULL) || (*list_str == NULL)) + return -1; - DHD_TRACE(("%s :size=%d left=%d\n", - (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + for (str = *list_str; str != NULL; str = ptr) { + + /* check for next TAG */ + if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { + *list_str = str + strlen(GET_CHANNEL); + return idx; } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; + + if ((ptr = strchr(str, ',')) != NULL) { + *ptr++ = '\0'; } - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); + if (strlen(str) > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); return -1; } + + if (strlen(str) == 0) + ssid[idx].SSID_len = 0; + + if (idx < max) { + bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); + strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); + ssid[idx].SSID_len = strlen(str); + } + idx++; } + return idx; +} + +/* + * Parse channel list from iwpriv CSCAN + */ +int +wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr = NULL; + + if ((list_str == NULL)||(*list_str == NULL)) + return -1; + str = *list_str; + num = 0; + while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { + val = (int)strtoul(str, &endptr, 0); + if (endptr == str) { + printf("could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, *list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", + channel_num, *list_str)); + return -1; + } + + channel_list[num++] = (uint16)val; + } *list_str = str; - return idx; + return num; } + +#endif diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c similarity index 97% rename from drivers/net/wireless/bcmdhd/dhd_custom_gpio.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c index f1482f89f343cf931525a8ccbe0960c2a969d912..fba369c895427b9c31c753e488f7a1cb324624b6 100644 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_gpio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * -* $Id: dhd_custom_gpio.c 595011 2015-10-26 05:41:56Z $ +* $Id: dhd_custom_gpio.c 684939 2017-02-15 02:39:44Z $ */ #include @@ -33,6 +33,9 @@ #include #include +#if defined(WL_WIRELESS_EXT) +#include +#endif #define WL_ERROR(x) printf x #define WL_TRACE(x) @@ -186,11 +189,10 @@ dhd_custom_get_mac_address(void *adapter, unsigned char *buf) #endif /* GET_CUSTOM_MAC_ENABLE */ struct cntry_locales_custom { - char iso_abbrev[WLC_CNTRY_BUF_SZ]; - char custom_locale[WLC_CNTRY_BUF_SZ]; - int32 custom_locale_rev; + char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ + char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ + int32 custom_locale_rev; /* Custom local revisin default -1 */ }; - /* Customized Locale table : OPTIONAL feature */ const struct cntry_locales_custom translate_custom_table[] = { /* Table should be filled out based on custom platform regulatory requirement */ diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_memprealloc.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_custom_memprealloc.c diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_dbg.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_dbg.h diff --git a/drivers/net/wireless/bcmdhd/dhd_flowring.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd_flowring.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c index 2612552a818ee4afde64b4f5130d1c6f69b602dc..89ebb2b9a9dd0c99d52a6d86750e186ec1f21227 100644 --- a/drivers/net/wireless/bcmdhd/dhd_flowring.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.c @@ -811,7 +811,7 @@ int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map) /* Set/Get flwo ring priority map */ int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set) { - uint8 iovbuf[24]; + uint8 iovbuf[24] = {0}; if (!set) { bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { diff --git a/drivers/net/wireless/bcmdhd/dhd_flowring.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_flowring.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_flowring.h diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_ip.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.c diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_ip.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_ip.h diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c similarity index 94% rename from drivers/net/wireless/bcmdhd/dhd_linux.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c index f51a04081148d4e3963e86add0e95520b6d0011e..555ce640adf86c272a699e885fc808e1836c7b0a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.c @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 676009 2016-12-20 02:54:41Z $ + * $Id: dhd_linux.c 718504 2017-08-31 02:38:08Z $ */ #include @@ -248,6 +248,12 @@ print_tainted() } #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ +/* Linux wireless extension support */ +#if defined(WL_WIRELESS_EXT) +#include +extern wl_iw_extra_params_t g_wl_iw_params; +#endif /* defined(WL_WIRELESS_EXT) */ + #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ @@ -370,6 +376,9 @@ typedef struct dhd_dump { /* Local private structure (extension of pub) */ typedef struct dhd_info { +#if defined(WL_WIRELESS_EXT) + wl_iw_t iw; /* wireless extensions state (must be first) */ +#endif /* defined(WL_WIRELESS_EXT) */ dhd_pub_t pub; dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */ @@ -718,6 +727,11 @@ static void dhd_dump_htsfhisto(histo_t *his, char *s); int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); + +#if defined(WL_WIRELESS_EXT) +struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); +#endif /* defined(WL_WIRELESS_EXT) */ + static void dhd_dpc(ulong data); /* forward decl */ extern int dhd_wait_pend8021x(struct net_device *dev); @@ -1427,7 +1441,6 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) int power_mode = PM_MAX; #endif /* SUPPORT_PM2_ONLY */ /* wl_pkt_filter_enable_t enable_parm; */ - char iovbuf[32]; int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ #ifndef ENABLE_FW_ROAM_SUSPEND uint roamvar = 1; @@ -1471,25 +1484,22 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) * one side effect is a chance to miss BC/MC packet. */ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), - TRUE, 0) < 0) + if (dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, + sizeof(bcn_li_dtim), NULL, 0, TRUE) < 0) DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); #ifndef ENABLE_FW_ROAM_SUSPEND /* Disable firmware roaming during suspend */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), + NULL, 0, TRUE); #endif /* ENABLE_FW_ROAM_SUSPEND */ if (FW_SUPPORTED(dhd, ndoe)) { /* enable IPv6 RA filter in firmware during suspend */ nd_ra_filter = 1; - bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", + (char *)&nd_ra_filter, sizeof(nd_ra_filter), + NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("failed to set nd_ra_filter (%d)\n", ret)); } @@ -1511,25 +1521,21 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) #endif /* PKT_FILTER_SUPPORT */ /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, + sizeof(bcn_li_dtim), NULL, 0, TRUE); #ifndef ENABLE_FW_ROAM_SUSPEND roamvar = dhd_roam_disable; - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, - sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), + NULL, 0, TRUE); #endif /* ENABLE_FW_ROAM_SUSPEND */ if (FW_SUPPORTED(dhd, ndoe)) { /* disable IPv6 RA filter in firmware during suspend */ nd_ra_filter = 0; - bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); + ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", + (char *)&nd_ra_filter, sizeof(nd_ra_filter), + NULL, 0, TRUE); + if (ret < 0) + DHD_ERROR(("nd_ra_filter: %d\n", ret)); } } } @@ -1890,35 +1896,14 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) * were trying to set some addresses and dongle rejected it... */ - buflen = sizeof("allmulti") + sizeof(allmulti); - if (!(buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx))); - return; - } allmulti = htol32(allmulti); - - if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { - DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", - dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen)); - MFREE(dhd->pub.osh, buf, buflen); - return; - } - - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_iovar(&dhd->pub, ifidx, "allmulti", (char *)&allmulti, + sizeof(allmulti), NULL, 0, TRUE); if (ret < 0) { DHD_ERROR(("%s: set allmulti %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); + dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); } - MFREE(dhd->pub.osh, buf, buflen); - /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ #ifdef MCAST_LIST_ACCUMULATION @@ -1951,21 +1936,10 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) int _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) { - char buf[32]; - wl_ioctl_t ioc; int ret; - if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { - DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx))); - return -1; - } - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = 32; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_iovar(&dhd->pub, ifidx, "cur_etheraddr", (char *)addr, + ETHER_ADDR_LEN, NULL, 0, TRUE); if (ret < 0) { DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); } else { @@ -2052,12 +2026,10 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) #ifndef PCIE_FULL_DONGLE /* Turn on AP isolation in the firmware for interfaces operating in AP mode */ if (FW_SUPPORTED((&dhd->pub), ap) && !(DHD_IF_ROLE_STA(if_event->event.role))) { - char iovbuf[WLC_IOCTL_SMLEN]; uint32 var_int = 1; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx); + ret = dhd_iovar(&dhd->pub, ifidx, "ap_isolate", (char *)&var_int, sizeof(var_int), + NULL, 0, TRUE); if (ret != BCME_OK) { DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__)); @@ -3521,24 +3493,15 @@ dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) static int dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) { - wl_ioctl_t ioc; char buf[32]; int ret; - memset(&ioc, 0, sizeof(ioc)); + ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", NULL, 0, (char *)buf, sizeof(buf), FALSE); - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = FALSE; - - strncpy(buf, "toe_ol", sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - /* Check for older dongle image that doesn't support toe_ol */ + if (ret < 0) { if (ret == -EIO) { - DHD_ERROR(("%s: toe not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); + DHD_ERROR(("%s: toe not supported by device\n", dhd_ifname(&dhd->pub, + ifidx))); return -EOPNOTSUPP; } @@ -3554,37 +3517,20 @@ dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) static int dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) { - wl_ioctl_t ioc; - char buf[32]; int toe, ret; - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = TRUE; - /* Set toe_ol as requested */ - - strncpy(buf, "toe_ol", sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); - - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", (char *)&toe_ol, sizeof(toe_ol), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); return ret; } /* Enable toe globally only if any components are enabled. */ - toe = (toe_ol != 0); - - strcpy(buf, "toe"); - memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); - - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + ret = dhd_iovar(&dhd->pub, ifidx, "toe", (char *)&toe, sizeof(toe), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); return ret; } @@ -3599,26 +3545,23 @@ void dhd_set_scb_probe(dhd_pub_t *dhd) #define NUM_SCB_MAX_PROBE 3 int ret = 0; wl_scb_probe_t scb_probe; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; - - memset(&scb_probe, 0, sizeof(wl_scb_probe_t)); if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) return; - bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf)); - - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "scb_probe", NULL, 0, (char *)&scb_probe, sizeof(wl_scb_probe_t), + FALSE); + if (ret < 0) { DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__)); - - memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t)); + } scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE; - bcm_mkiovar("scb_probe", (char *)&scb_probe, - sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "scb_probe", (char *)&scb_probe, + sizeof(wl_scb_probe_t), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__)); + } #undef NUM_SCB_MAX_PROBE return; } @@ -3993,6 +3936,17 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) return -1; } +#if defined(WL_WIRELESS_EXT) + /* linux wireless extensions */ + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + /* may recurse, do NOT lock */ + ret = wl_iw_ioctl(net, ifr, cmd); + DHD_PERIM_UNLOCK(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } +#endif /* defined(WL_WIRELESS_EXT) */ + #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) if (cmd == SIOCETHTOOL) { ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); @@ -4194,21 +4148,19 @@ extern bool g_first_broadcast_scan; #ifdef WL11U static int dhd_interworking_enable(dhd_pub_t *dhd) { - char iovbuf[WLC_IOCTL_SMLEN]; uint32 enable = true; int ret = BCME_OK; - bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "interworking", (char *)&enable, sizeof(enable), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); } if (ret == BCME_OK) { /* basic capabilities for HS20 REL2 */ uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF; - bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "wnm", (char *)&cap, sizeof(cap), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret)); } } @@ -4906,6 +4858,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd_monitor_init(&dhd->pub); dhd_state |= DHD_ATTACH_STATE_CFG80211; #endif +#if defined(WL_WIRELESS_EXT) + /* Attach and link in the iw */ + if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { + if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { + DHD_ERROR(("wl_iw_attach failed\n")); + goto fail; + } + dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; + } +#endif /* defined(WL_WIRELESS_EXT) */ #ifdef SHOW_LOGTRACE dhd_init_logstrs_array(&dhd->event_data); @@ -5249,7 +5211,6 @@ dhd_bus_start(dhd_pub_t *dhdp) #ifdef WLTDLS int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) { - char iovbuf[WLC_IOCTL_SMLEN]; uint32 tdls = tdls_on; int ret = 0; uint32 tdls_auto_op = 0; @@ -5262,8 +5223,8 @@ int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_ad if (dhd->tdls_enable == tdls_on) goto auto_mode; - bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "tdls_enable", (char *)&tdls, sizeof(tdls), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); goto exit; } @@ -5271,31 +5232,29 @@ int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_ad auto_mode: tdls_auto_op = auto_on; - bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), NULL, + 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); goto exit; } if (tdls_auto_op) { - bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, - sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "tdls_idle_time", (char *)&tdls_idle_time, + sizeof(tdls_idle_time), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); goto exit; } - bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "tdls_rssi_high", (char *)&tdls_rssi_high, + sizeof(tdls_rssi_high), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); goto exit; } - bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "tdls_rssi_low", (char *)&tdls_rssi_low, + sizeof(tdls_rssi_low), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); goto exit; } @@ -5412,9 +5371,9 @@ dhd_get_concurrent_capabilites(dhd_pub_t *dhd) else { /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ memset(buf, 0, sizeof(buf)); - bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)buf, + sizeof(buf), FALSE); + if (ret < 0) { DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); return 0; } @@ -5617,9 +5576,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef GET_CUSTOM_MAC_ENABLE ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet); if (!ret) { - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)&ea_addr, ETHER_ADDR_LEN, NULL, 0, + TRUE); if (ret < 0) { DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); ret = BCME_NOTUP; @@ -5629,10 +5587,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } else { #endif /* GET_CUSTOM_MAC_ENABLE */ /* Get the default device MAC address directly from firmware */ - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "cur_etheraddr", NULL, 0, (char *)&buf, sizeof(buf), FALSE); + if (ret < 0) { DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); ret = BCME_NOTUP; goto done; @@ -5646,9 +5602,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* get a capabilities from firmware */ memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities)); - bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities, - sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "cap", NULL, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities), + FALSE); + if (ret < 0) { DHD_ERROR(("%s: Get Capability failed (error=%d)\n", __FUNCTION__, ret)); goto done; @@ -5675,8 +5631,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) iovbuf[4] = (unsigned char)(rand_mac >> 8); iovbuf[5] = (unsigned char)(rand_mac >> 16); - bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)iovbuf, ETHER_ADDR_LEN, NULL, 0, + TRUE); if (ret < 0) { DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); } else @@ -5684,16 +5640,19 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* SET_RANDOM_MAC_SOFTAP */ #if !defined(AP) && defined(WL_CFG80211) /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, + sizeof(mpc), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); } #endif #ifdef SOFTAP_UAPSD_OFF - bcm_mkiovar("wme_apsd", (char *)&wme_apsd, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", __FUNCTION__, ret)); + ret = dhd_iovar(dhd, 0, "wme_apsd", (char *)&wme_apsd, sizeof(wme_apsd), NULL, 0, + TRUE); + if (ret < 0) { + DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", + __FUNCTION__, ret)); + } #endif /* SOFTAP_UAPSD_OFF */ #ifdef SET_RETRY_LIMIT if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, (char *)&srl, @@ -5741,11 +5700,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Check if we are enabling p2p */ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, + TRUE); + if (ret < 0) DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); - } #if defined(SOFTAP_AND_GC) if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP, @@ -5755,14 +5713,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); ETHER_SET_LOCALADDR(&p2p_ea); - bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, - ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "p2p_da_override", (char *)&p2p_ea, sizeof(p2p_ea), + NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); - } else { + else DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); - } } #else (void)concurrent_mode; @@ -5773,9 +5729,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { - bcm_mkiovar("country", (char *)&dhd->dhd_cspec, - sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), + NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); } @@ -5783,8 +5739,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (somc_disable_vht) { #endif /* ! DISABLE_11AC */ - bcm_mkiovar("vhtmode", (char *)&vhtmode, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "vhtmode", (char *)&vhtmode, sizeof(vhtmode), NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret)); else DHD_ERROR(("%s VHT(11ac) mode is disabled\n", __FUNCTION__)); @@ -5793,14 +5749,14 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* ! DISABLE_11AC */ /* Set Listen Interval */ - bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "assoc_listen", (char *)&listen_interval, sizeof(listen_interval), + NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ #if defined(ROAM_ENABLE) if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, @@ -5812,25 +5768,23 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, sizeof(roam_delta), TRUE, 0)) < 0) DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); - bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&roam_fullscan_period, + sizeof(roam_fullscan_period), NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); #ifdef ROAM_AP_ENV_DETECTION if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { - bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode, - 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK) + if (dhd_iovar(dhd, 0, "roam_env_detection", (char *)&roam_env_mode, + sizeof(roam_env_mode), NULL, 0, TRUE) == BCME_OK) dhd->roam_env_detection = TRUE; - else { + else dhd->roam_env_detection = FALSE; - } } #endif /* ROAM_AP_ENV_DETECTION */ #endif /* ROAM_ENABLE */ #ifdef BCMCCX - bcm_mkiovar("ccx_enable", (char *)&ccx, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "ccx_enable", (char *)&ccx, sizeof(ccx), NULL, 0, TRUE); #endif /* BCMCCX */ #ifdef WLTDLS /* by default TDLS on and auto mode off */ @@ -5839,9 +5793,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef DHD_ENABLE_LPC /* Set lpc 1 */ - bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); } #endif /* DHD_ENABLE_LPC */ @@ -5850,26 +5803,23 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), + NULL, 0, TRUE); #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) /* enable credall to reduce the chance of no bus credit happened. */ - bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "bus:credall", (char *)&credall, sizeof(credall), NULL, 0, TRUE); #endif #if defined(BCMSDIO) if (glom != DEFAULT_GLOM_VALUE) { DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "bus:txglom", (char *)&glom, sizeof(glom), NULL, 0, TRUE); } #endif /* defined(BCMSDIO) */ /* Setup timeout if Beacons are lost and roam is off to report link down */ - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, sizeof(bcn_timeout), NULL, 0, TRUE); #ifdef SOMC_WLAN_SCAN_NPROBES { const uint32 scan_nprobes = SOMC_WLAN_SCAN_NPROBES; @@ -5882,26 +5832,22 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef SOMC_WLAN_ENABLE_SCAN_PS { const uint32 scan_ps = 1; - bcm_mkiovar("scan_ps", (char *)&scan_ps, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + dhd_iovar(dhd, 0, "scan_ps", (char *)&scan_ps, sizeof(scan_ps), NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s scan_ps failed %d\n", __FUNCTION__, ret)); } #endif #ifdef DISABLE_BCN_DLY /* Set bcn_to_dly to delay link down until roam complete */ - bcm_mkiovar("bcn_to_dly", (char *)&bcn_to_dly, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, sizeof(bcn_to_dly), NULL, 0, TRUE); #endif /* Setup assoc_retry_max count to reconnect target AP in dongle */ - bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "assoc_retry_max", (char *)&retry_max, sizeof(retry_max), NULL, 0, TRUE); #if defined(AP) && !defined(WLP2P) /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); + dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); #endif /* defined(AP) && !defined(WLP2P) */ @@ -5929,16 +5875,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* defined(KEEP_ALIVE) */ #ifdef USE_WL_TXBF - bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "txbf", (char *)&txbf, sizeof(txbf), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); } #endif /* USE_WL_TXBF */ #ifdef DISABLE_TXBFR - bcm_mkiovar("txbf_bfr_cap", (char *)&txbf_bfr_cap, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "txbf_bfr_cap", (char *)&txbf_bfr_cap, sizeof(txbf_bfr_cap), NULL, + 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); } #endif /* DISABLE_TXBFR */ @@ -5951,16 +5896,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* USE_WL_FRAMEBURST */ #ifdef DHD_SET_FW_HIGHSPEED /* Set ack_ratio */ - bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "ack_ratio", (char *)&ack_ratio, sizeof(ack_ratio), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret)); } /* Set ack_ratio_depth */ - bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "ack_ratio_depth", (char *)&ack_ratio_depth, + sizeof(ack_ratio_depth), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret)); } #endif /* DHD_SET_FW_HIGHSPEED */ @@ -5975,9 +5919,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE; #endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */ if (ampdu_ba_wsize != 0) { - bcm_mkiovar("ampdu_ba_wsize", (char *)&du_ba_wsize, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, + sizeof(ampdu_ba_wsize), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", __FUNCTION__, ampdu_ba_wsize, ret)); } @@ -5995,17 +5939,16 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { aibss = 1; - bcm_mkiovar("aibss", (char *)&aibss, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "aibss", (char *)&aibss, sizeof(aibss), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set aibss to %d failed %d\n", __FUNCTION__, aibss, ret)); } #ifdef WLAIBSS_PS aibss_ps = 1; - bcm_mkiovar("aibss_ps", (char *)&aibss_ps, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "aibss_ps", (char *)&aibss_ps, sizeof(aibss_ps), + NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set aibss PS to %d failed %d\n", __FUNCTION__, aibss, ret)); } @@ -6018,10 +5961,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; bcn_config.len = sizeof(bcn_config); - bcm_mkiovar("aibss_bcn_force_config", (char *)&bcn_config, - sizeof(aibss_bcn_force_config_t), iov_buf, WLC_IOCTL_SMLEN); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iov_buf, - WLC_IOCTL_SMLEN, TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "aibss_bcn_force_config", (char *)&bcn_config, + sizeof(aibss_bcn_force_config_t), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n", __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR, AIBSS_BCN_FLOOD_DUR, ret)); @@ -6031,9 +5973,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(CUSTOM_AMPDU_MPDU) ampdu_mpdu = CUSTOM_AMPDU_MPDU; if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { - bcm_mkiovar("ampdu_mpdu", (char *)&du_mpdu, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "ampdu_mpdu", (char *)&du_mpdu, sizeof(ampdu_mpdu), + NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); } @@ -6043,9 +5985,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(CUSTOM_AMPDU_RELEASE) ampdu_release = CUSTOM_AMPDU_RELEASE; if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) { - bcm_mkiovar("ampdu_release", (char *)&du_release, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "ampdu_release", (char *)&du_release, + sizeof(ampdu_release), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set ampdu_release to %d failed %d\n", __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret)); } @@ -6055,9 +5997,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(CUSTOM_AMSDU_AGGSF) amsdu_aggsf = CUSTOM_AMSDU_AGGSF; if (amsdu_aggsf != 0) { - bcm_mkiovar("amsdu_aggsf", (char *)&amsdu_aggsf, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "amsdu_aggsf", (char *)&amsdu_aggsf, sizeof(amsdu_aggsf), + NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n", __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret)); } @@ -6065,31 +6007,32 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* CUSTOM_AMSDU_AGGSF */ #ifdef SUPPORT_2G_VHT - bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, sizeof(vht_features), + NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); } #endif /* SUPPORT_2G_VHT */ #ifdef CUSTOM_PSPRETEND_THR /* Turn off MPC in AP mode */ - bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "pspretend_threshold", (char *)&pspretend_thr, + sizeof(pspretend_thr), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", __FUNCTION__, ret)); } #endif - bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "buf_key_b4_m4", (char *)&buf_key_b4_m4, sizeof(buf_key_b4_m4), + NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); } /* Read event_msgs mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf), FALSE); + if (ret < 0) { DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); goto done; } @@ -6154,11 +6097,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAIBSS setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ +#ifdef SHOW_LOGTRACE setbit(eventmask, WLC_E_TRACE); +#else + clrbit(eventmask, WLC_E_TRACE); +#endif /* SHOW_LOGTRACE */ setbit(eventmask, WLC_E_CSA_COMPLETE_IND); /* Write updated Event mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); goto done; } @@ -6176,8 +6123,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; /* Read event_msgs_ext mask */ - bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, WLC_IOCTL_SMLEN); - ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, WLC_IOCTL_SMLEN, FALSE, 0); + ret2 = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, + WLC_IOCTL_SMLEN, FALSE); if (ret2 != BCME_UNSUPPORTED) ret = ret2; if (ret2 == 0) { /* event_msgs_ext must be supported */ @@ -6195,10 +6142,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) eventmask_msg->ver = EVENTMSGS_VER; eventmask_msg->command = EVENTMSGS_SET_MASK; eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, - msglen, iov_buf, WLC_IOCTL_SMLEN); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iov_buf, WLC_IOCTL_SMLEN, TRUE, 0)) < 0) { + ret = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, NULL, 0, + TRUE); + if (ret < 0) { DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); goto done; } @@ -6252,28 +6198,26 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_set_packet_filter(dhd); #endif /* PKT_FILTER_SUPPORT */ #ifdef DISABLE_11N - bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "nmode", (char *)&nmode, sizeof(nmode), NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); #endif /* DISABLE_11N */ #ifdef AMPDU_VO_ENABLE tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */ tid.enable = TRUE; - bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */ tid.enable = TRUE; - bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_iovar(dhd, 0, "ampdu_tid", (char *)&tid, sizeof(tid), NULL, 0, TRUE); #endif #ifdef SOMC_MAX_ASSOC_NUM { /* Set the maximum number of stations for P2P / SoftAP */ const uint32 max = SOMC_MAX_ASSOC_NUM; - bcm_mkiovar("maxassoc", (char*)&max, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + dhd_iovar(dhd, 0, "maxassoc", (char *)&max, sizeof(max), NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s: maxassoc set failed %d\n", __FUNCTION__, ret)); } #endif /* SOMC_MAX_ASSOC_NUM */ @@ -6281,8 +6225,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; - bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "ver", NULL, 0, (char *)&buf, sizeof(buf), FALSE); + if (ret < 0) DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); else { bcmstrtok(&ptr, "\n", 0); @@ -6315,8 +6259,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #ifndef DISABLE_11N - bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf)); - if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, sizeof(hostreorder), + NULL, 0, TRUE); + if (ret2 < 0) { DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); if (ret2 != BCME_UNSUPPORTED) ret = ret2; @@ -6328,9 +6273,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s ampdu_hostreorder fail WL_DOWN : %d, hostreorder :%d\n", __FUNCTION__, ret2, hostreorder)); - bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, - iovbuf, sizeof(iovbuf)); - ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, + sizeof(hostreorder), NULL, 0, TRUE); DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2)); if (ret2 != BCME_UNSUPPORTED) ret = ret2; @@ -6355,8 +6299,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ if (FW_SUPPORTED(dhd, ap)) { wl_ap_isolate = AP_ISOLATE_SENDUP_ALL; - bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + ret = dhd_iovar(dhd, 0, "ap_isolate", (char *)&wl_ap_isolate, sizeof(wl_ap_isolate), + NULL, 0, TRUE); + if (ret < 0) DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); } #endif /* PCIE_FULL_DONGLE */ @@ -6387,28 +6332,97 @@ done: return ret; } - int -dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) +dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, + uint res_len, int set) { - char buf[strlen(name) + 1 + cmd_len]; - int len = sizeof(buf); + char *buf = NULL; + int input_len; wl_ioctl_t ioc; int ret; - len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); + if (res_len > WLC_IOCTL_MAXLEN || param_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; - memset(&ioc, 0, sizeof(ioc)); + input_len = strlen(name) + 1 + param_len; + if (input_len > WLC_IOCTL_MAXLEN) + return BCME_BADARG; - ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = set; + buf = NULL; + if (set) { + if (res_buf || res_len != 0) { + DHD_ERROR(("%s: SET wrong arguemnet\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + buf = kzalloc(input_len, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - if (!set && ret >= 0) - memcpy(cmd_buf, buf, cmd_len); + ioc.cmd = WLC_SET_VAR; + ioc.buf = buf; + ioc.len = input_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + } else { + if (!res_buf || !res_len) { + DHD_ERROR(("%s: GET failed. resp_buf NULL or length 0.\n", __FUNCTION__)); + ret = BCME_BADARG; + goto exit; + } + + if (res_len < input_len) { + DHD_INFO(("%s: res_len(%d) < input_len(%d)\n", __FUNCTION__, + res_len, input_len)); + buf = kzalloc(input_len, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); + ret = BCME_NOMEM; + goto exit; + } + ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_GET_VAR; + ioc.buf = buf; + ioc.len = input_len; + ioc.set = set; + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + + if (ret == BCME_OK) { + memcpy(res_buf, buf, res_len); + } + } else { + memset(res_buf, 0, res_len); + ret = bcm_mkiovar(name, param_buf, param_len, res_buf, res_len); + if (!ret) { + ret = BCME_NOMEM; + goto exit; + } + + ioc.cmd = WLC_GET_VAR; + ioc.buf = res_buf; + ioc.len = res_len; + ioc.set = set; + + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + } + } +exit: + kfree(buf); return ret; } @@ -6802,6 +6816,15 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) net->ethtool_ops = &dhd_ethtool_ops; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ +#if defined(WL_WIRELESS_EXT) +#if WIRELESS_EXT < 19 + net->get_wireless_stats = dhd_get_wireless_stats; +#endif /* WIRELESS_EXT < 19 */ +#if WIRELESS_EXT > 12 + net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#endif /* defined(WL_WIRELESS_EXT) */ + dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); @@ -6824,7 +6847,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, MAC2STRDBG(net->dev_addr)); -#if defined(SOFTAP) && !defined(WL_CFG80211) +#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) wl_iw_iscan_set_scan_broadcast_prep(net, 1); #endif @@ -6948,6 +6971,13 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ +#if defined(WL_WIRELESS_EXT) + if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { + /* Detatch and unlink in the iw */ + wl_iw_detach(); + } +#endif /* defined(WL_WIRELESS_EXT) */ + /* delete all interfaces, start with virtual */ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { int i = 1; @@ -7330,7 +7360,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif DHD_PERIM_UNLOCK(pub); @@ -7361,7 +7391,7 @@ dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition, bool *pending) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); #else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; + timeout = dhd_ioctl_timeout_msec * msecs_to_jiffies(1); #endif DHD_PERIM_UNLOCK(pub); @@ -7599,6 +7629,26 @@ void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) { } +#if defined(WL_WIRELESS_EXT) +struct iw_statistics * +dhd_get_wireless_stats(struct net_device *dev) +{ + int res = 0; + dhd_info_t *dhd = DHD_DEV_INFO(dev); + + if (!dhd->pub.up) { + return NULL; + } + + res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); + + if (res == 0) + return &dhd->iw.wstats; + else + return NULL; +} +#endif /* defined(WL_WIRELESS_EXT) */ + static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, wl_event_msg_t *event, void **data) @@ -7617,6 +7667,21 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, uint16 pktlen, if (bcmerror != BCME_OK) return (bcmerror); +#if defined(WL_WIRELESS_EXT) + if (event->bsscfgidx == 0) { + /* + * Wireless ext is on primary interface only + */ + + ASSERT(dhd->iflist[*ifidx] != NULL); + ASSERT(dhd->iflist[*ifidx]->net != NULL); + + if (dhd->iflist[*ifidx]->net) { + wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); + } + } +#endif /* defined(WL_WIRELESS_EXT) */ + #ifdef WL_CFG80211 ASSERT(dhd->iflist[*ifidx] != NULL); ASSERT(dhd->iflist[*ifidx]->net != NULL); @@ -7704,7 +7769,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; + int timeout = IOCTL_RESP_TIMEOUT * msecs_to_jiffies(1); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); @@ -8175,12 +8240,11 @@ void * dhd_dev_hotlist_scan_event(struct net_device *dev, /* Linux wrapper to call common dhd_process_full_gscan_result */ void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, uint32 len, int *send_evt_bytes) + const void *data, uint32 len, int *send_evt_bytes) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return dhd_process_full_gscan_result(&dhd->pub, data, len, - send_evt_bytes); + return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); } void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) @@ -8242,7 +8306,7 @@ dhd_dev_set_lazy_roam_cfg(struct net_device *dev, roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; } err = dhd_iovar(&(dhd->pub), 0, "roam_exp_params", (char *)&roam_exp_cfg, - sizeof(roam_exp_cfg), 1); + sizeof(roam_exp_cfg), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); } @@ -8263,7 +8327,7 @@ dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) } err = dhd_iovar(&(dhd->pub), 0, "roam_exp_params", (char *)&roam_exp_cfg, - sizeof(roam_exp_cfg), 1); + sizeof(roam_exp_cfg), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); } else { @@ -8284,8 +8348,8 @@ dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; len = sizeof(wl_bssid_pref_cfg_t); len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_bssid_pref", (char *)bssid_pref, - len, 1); + err = dhd_iovar(&dhd->pub, 0, "roam_exp_bssid_pref", + (char *)bssid_pref, len, NULL, 0, TRUE); if (err != BCME_OK) { DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); } @@ -8335,8 +8399,8 @@ dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whi } ssid_whitelist->version = SSID_WHITELIST_VERSION; ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, - len, 1); + err = dhd_iovar(&dhd->pub, 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, len, NULL, + 0, TRUE); if (err != BCME_OK) { DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); } @@ -8388,11 +8452,9 @@ dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 /* * Get current mkeep-alive status. */ - bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), - pbuf, TEMP_BUF_SIZE); - - if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE, - FALSE, 0)) < 0) { + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, + TEMP_BUF_SIZE, FALSE); + if (res < 0) { DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); goto exit; } else { @@ -8490,11 +8552,8 @@ int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) { char *pbuf; - const char *str; wl_mkeep_alive_pkt_t mkeep_alive_pkt; wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; int res = BCME_ERROR; int i; @@ -8515,9 +8574,9 @@ dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) return res; } - bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE); - - if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE, FALSE, 0)) < 0) { + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, + sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE, FALSE); + if (res < 0) { DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); goto exit; } else { @@ -8542,29 +8601,20 @@ dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id) if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - memset(pbuf, 0, TEMP_BUF_SIZE); - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(pbuf, str, str_len); - pbuf[str_len] = '\0'; - - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); mkeep_alive_pkt.period_msec = 0; - buf_len = str_len + 1; mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; /* * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no * guarantee that the buffer is properly aligned. */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); + res = dhd_iovar(dhd_pub, 0, "mkeep_alive", + (char *)&mkeep_alive_pkt, + WL_MKEEP_ALIVE_FIXED_LEN, NULL, 0, TRUE); } else { DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); res = BCME_NOTFOUND; @@ -8587,8 +8637,8 @@ dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, rssi_monitor.max_rssi = max_rssi; rssi_monitor.min_rssi = min_rssi; rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; - err = dhd_iovar(&(dhd->pub), 0, "rssi_monitor", (char *)&rssi_monitor, - sizeof(rssi_monitor), 1); + err = dhd_iovar(&dhd->pub, 0, "rssi_monitor", (char *)&rssi_monitor, sizeof(rssi_monitor), + NULL, 0, TRUE); if (err < 0 && err != BCME_UNSUPPORTED) { DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); } @@ -8636,7 +8686,7 @@ dhd_set_rand_mac_oui(dhd_pub_t *dhd) DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], rand_mac_oui[1], rand_mac_oui[2])); - err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), 1); + err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); } @@ -8697,6 +8747,9 @@ static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) rtnl_lock(); dev_close(dev); rtnl_unlock(); +#if defined(WL_WIRELESS_EXT) + wl_iw_send_priv_event(dev, "HANG"); +#endif #if defined(WL_CFG80211) wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); #endif @@ -10118,7 +10171,6 @@ static void dhd_dump_latency(void) static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) { - wl_ioctl_t ioc; char buf[32]; int ret; uint32 s1, s2; @@ -10128,18 +10180,11 @@ dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) uint32 high; } tsf_buf; - memset(&ioc, 0, sizeof(ioc)); memset(&tsf_buf, 0, sizeof(tsf_buf)); - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = FALSE; - - strncpy(buf, "tsf", sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; s1 = dhd_get_htsf(dhd, 0); - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + ret = dhd_iovar(&dhd->pub, ifidx, "tsf", NULL, 0, buf, sizeof(buf), FALSE); + if (ret < 0) { if (ret == -EIO) { DHD_ERROR(("%s: tsf is not supported by device\n", dhd_ifname(&dhd->pub, ifidx))); diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h similarity index 97% rename from drivers/net/wireless/bcmdhd/dhd_linux.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h index a245854db304f26ea602678d97308175710e2d09..529f2be46fbbf0ddcd8767cb592148ecbc5b1f40 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux.h @@ -40,7 +40,10 @@ #ifdef DHD_WMF #include #endif - +/* Linux wireless extension support */ +#if defined(WL_WIRELESS_EXT) +#include +#endif /* defined(WL_WIRELESS_EXT) */ #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_platdev.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_linux_platdev.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_platdev.c diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_sched.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_linux_sched.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_sched.c diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_linux_wq.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.c diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_linux_wq.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_linux_wq.h diff --git a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd_msgbuf.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c index bc7222eb276baa050e36823e7013adea073cfdd9..2998dd4c4d6e6ee2a9a3a05a47def11e44233bbc 100644 --- a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_msgbuf.c @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_msgbuf.c 676009 2016-12-20 02:54:41Z $ + * $Id: dhd_msgbuf.c 687068 2017-02-27 11:13:31Z $ */ #include #include diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd_pcie.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c index c27accd66cda4cb0128229c99cbb138e80398330..03fcc06aa31f3066066697a9590030648e0aaeca 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pcie.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.c @@ -742,12 +742,9 @@ dhdpcie_bus_release(dhd_bus_t *bus) MFREE(osh, bus, sizeof(dhd_bus_t)); } - DHD_TRACE(("%s: Exit\n", __FUNCTION__)); - } - void dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) { @@ -2927,6 +2924,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) bus->dhd->up = FALSE; if (bus->dhd->busstate != DHD_BUS_DOWN) { if (bus->intr) { + dhdpcie_bus_intr_disable(bus); dhdpcie_free_irq(bus); } #ifdef BCMPCIE_OOB_HOST_WAKE diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_pcie.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie.h diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie_linux.c similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_pcie_linux.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_pcie_linux.c diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c similarity index 98% rename from drivers/net/wireless/bcmdhd/dhd_pno.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c index 5566f7019ae770bda891bf78acbef71d69842241..838fe5d2898c8bf413ef6120c4b985a0dad250c6 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.c @@ -91,8 +91,7 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 - -#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) +#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) #define EVENT_MAX_NETCNT \ ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ / sizeof(wl_pfn_net_info_t) + 1) @@ -125,14 +124,14 @@ dhd_pno_clean(dhd_pub_t *dhd) _pno_state = PNO_GET_PNOSTATE(dhd); DHD_PNO(("%s enter\n", __FUNCTION__)); /* Disable PNO */ - err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), 1); + err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", __FUNCTION__, err)); goto exit; } _pno_state->pno_status = DHD_PNO_DISABLED; - err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, 1); + err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", __FUNCTION__, err)); @@ -229,7 +228,7 @@ _dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int s DHD_PNO(("%s enter\n", __FUNCTION__)); - err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, 1); + err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__)); goto exit; @@ -257,7 +256,7 @@ _dhd_pno_suspend(dhd_pub_t *dhd) DHD_PNO(("%s enter\n", __FUNCTION__)); _pno_state = PNO_GET_PNOSTATE(dhd); - err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), 1); + err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); goto exit; @@ -297,7 +296,7 @@ _dhd_pno_enable(dhd_pub_t *dhd, int enable) } } /* Enable/Disable PNO */ - err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), 1); + err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); goto exit; @@ -492,13 +491,13 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t #endif /* GSCAN_SUPPORT */ int _tmp = pfn_param.bestn; /* set bestn to calculate the max mscan which firmware supports */ - err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 1); + err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); goto exit; } /* get max mscan which the firmware supports */ - err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 0); + err = dhd_iovar(dhd, 0, "pfnmem", NULL, 0, (char *)&_tmp, sizeof(_tmp), FALSE); if (err < 0) { DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); goto exit; @@ -507,7 +506,7 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, pfn_param.mscan)); } - err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1); + err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); goto exit; @@ -567,8 +566,8 @@ _dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, ssids_list[i].SSID_len); pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; - err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, - sizeof(pfn_element), 1); + err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, sizeof(wl_pfn_t), + NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); goto exit; @@ -624,12 +623,13 @@ _dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, { int err = BCME_OK; int i, j; - uint32 chan_buf[WL_NUMCHANNELS]; + uint32 chan_buf[WL_NUMCHANNELS+1]; wl_uint32_list_t *list; NULL_CHECK(dhd, "dhd is NULL", err); if (*nchan) { NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); } + memset(&chan_buf, 0, sizeof(chan_buf)); list = (wl_uint32_list_t *) (void *)chan_buf; list->count = htod32(WL_NUMCHANNELS); err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); @@ -860,7 +860,8 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) pfncfg_param.channel_list[i] = channel_list[i]; pfncfg_param.channel_num = htod32(nchan); - err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), 1); + err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), NULL, 0, + TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); goto exit; @@ -955,7 +956,7 @@ _dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); } err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, - sizeof(wl_pfn_bssid_t) * nbssid, 1); + sizeof(wl_pfn_bssid_t) * nbssid, NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); goto exit; @@ -1199,7 +1200,7 @@ static int dhd_epno_set_ssid(dhd_pub_t *dhd, } if (num_visible_epno_ssid) { err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem, - mem_needed, 1); + mem_needed, NULL, 0, TRUE); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__, err)); @@ -1890,10 +1891,10 @@ dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); if ((_params->params_gscan.nbssid_hotlist + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { DHD_ERROR(("Excessive number of hotlist APs programmed %d\n", - (_params->params_gscan.nbssid_hotlist + - ptr->nbssid))); + (_params->params_gscan.nbssid_hotlist + + ptr->nbssid))); err = BCME_RANGE; goto exit; } @@ -2109,8 +2110,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) - MALLOCZ(dhd->osh, gscan_param_size); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); if (!pfn_gscan_cfg_t) { DHD_ERROR(("%s: failed to malloc memory of size %d\n", @@ -2125,6 +2125,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) } else { pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; } + pfn_gscan_cfg_t->flags = (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; @@ -2161,6 +2162,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) __FUNCTION__, err)); goto exit; } + if (gscan_params->nbssid_hotlist) { struct dhd_pno_bssid *iter, *next; wl_pfn_bssid_t *ptr; @@ -2229,7 +2231,6 @@ exit: (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); } return err; - } static wl_pfn_gscan_ch_bucket_cfg_t * @@ -2590,6 +2591,12 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) } plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } mutex_lock(&_pno_state->pno_mutex); @@ -2607,8 +2614,8 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) plbestnet->status = PFN_INCOMPLETE; tail = gscan_params->gscan_batch_cache; while (plbestnet->status != PFN_COMPLETE) { - memset(plbestnet, 0, PNO_BESTNET_LEN); - err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, + (char *)plbestnet, PNO_BESTNET_LEN, FALSE); if (err < 0) { DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", __FUNCTION__, err)); @@ -2837,8 +2844,8 @@ _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) DHD_PNO(("%s enter\n", __FUNCTION__)); memset(plbestnet, 0, PNO_BESTNET_LEN); while (plbestnet->status != PFN_COMPLETE) { - memset(plbestnet, 0, PNO_BESTNET_LEN); - err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, + (char *)plbestnet, PNO_BESTNET_LEN, FALSE); if (err < 0) { if (err == BCME_EPERM) { DHD_ERROR(("we cannot get the batching data " @@ -3489,8 +3496,7 @@ dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) } void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, - int *size) +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; @@ -3499,7 +3505,6 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, uint8 channel; uint32 mem_needed; struct timespec ts; - wl_event_gas_t *gas_data; u32 bi_ie_length = 0; u32 bi_ie_offset = 0; @@ -3511,16 +3516,14 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } - if ((len < sizeof(*gscan_result)) || (len < dtoh32(gscan_result->buflen)) || (dtoh32(gscan_result->buflen) > (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { - DHD_ERROR(("%s: invalid gscan buflen:%u\n", __func__, - dtoh32(gscan_result->buflen))); + DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, + dtoh32(gscan_result->buflen))); goto exit; } - if (!gscan_result->bss_info) { DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); goto exit; @@ -3532,31 +3535,16 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } - bi_ie_offset = dtoh32(bi->ie_offset); bi_ie_length = dtoh32(bi->ie_length); if ((bi_ie_offset + bi_ie_length) > bi_length) { DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", - __func__, bi_ie_length, bi_ie_offset)); + __FUNCTION__, bi_ie_length, bi_ie_offset)); goto exit; } - - if ((bi->SSID_len > DOT11_MAX_SSID_LEN)|| - (bi->ie_length > (*size - sizeof(wl_bss_info_t))) || - (bi->ie_offset < sizeof(wl_bss_info_t)) || - (bi->ie_offset > (sizeof(wl_bss_info_t) + bi->ie_length))){ - DHD_ERROR(("%s: tot:%d,SSID:%d,ie_len:%d,ie_off:%d\n", - __FUNCTION__, *size, bi->SSID_len, - bi->ie_length, bi->ie_offset)); - return NULL; - } - - gas_data = (wl_event_gas_t *)((uint8 *)data + bi->ie_offset + bi->ie_length); - - if (gas_data->data_len > (*size - (bi->ie_offset + bi->ie_length))) { - DHD_ERROR(("%s: wrong gas_data_len:%d\n", - __FUNCTION__, gas_data->data_len)); - return NULL; + if (bi->SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); + goto exit; } mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; @@ -3646,14 +3634,13 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; wl_pfn_net_info_t *net; - if ((pfn_result->count == 0) || - (pfn_result->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s event %d: incorrect results count:%d\n", - __FUNCTION__, event, pfn_result->count)); - return NULL; - } - if (pfn_result->version != PFN_SCANRESULT_VERSION) { + /* Check if count of pfn results is corrupted */ + if (pfn_result->count > EVENT_MAX_NETCNT) { + DHD_ERROR(("%s event %d: pfn results count %d" + "exceeds the max limit\n", __FUNCTION__, event, pfn_result->count)); + return NULL; + } DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, pfn_result->version, PFN_SCANRESULT_VERSION)); return NULL; @@ -3708,9 +3695,8 @@ void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *s gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - if ((results->count == 0) || (results->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s: wrong count:%d\n", __FUNCTION__, - results->count)); + if (!results->count || (results->count > EVENT_MAX_NETCNT)) { + DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count)); *send_evt_bytes = 0; return ptr; } @@ -3838,6 +3824,7 @@ int dhd_pno_init(dhd_pub_t *dhd) { int err = BCME_OK; dhd_pno_status_info_t *_pno_state; + char *buf = NULL; NULL_CHECK(dhd, "dhd is NULL", err); DHD_PNO(("%s enter\n", __FUNCTION__)); UNUSED_PARAMETER(_dhd_pno_suspend); @@ -3856,13 +3843,20 @@ int dhd_pno_init(dhd_pub_t *dhd) #ifdef GSCAN_SUPPORT init_waitqueue_head(&_pno_state->batch_get_wait); #endif /* GSCAN_SUPPORT */ - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0); + buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (!buf) { + DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__)); + return BCME_NOMEM; + } + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN, + FALSE); if (err == BCME_UNSUPPORTED) { _pno_state->wls_supported = FALSE; DHD_INFO(("Current firmware doesn't support" " Android Location Service\n")); } exit: + kfree(buf); return err; } int dhd_pno_deinit(dhd_pub_t *dhd) diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h similarity index 96% rename from drivers/net/wireless/bcmdhd/dhd_pno.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h index c05b3f361b14c021bdf8d976ec085254f2dd70ae..dc99441fa47aacf109260e9e9119d154b5628a81 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_pno.h @@ -349,18 +349,18 @@ typedef struct gscan_results_cache { } gscan_results_cache_t; typedef struct dhd_pno_gscan_capabilities { - int max_scan_cache_size; - int max_scan_buckets; - int max_ap_cache_per_scan; - int max_rssi_sample_size; - int max_scan_reporting_threshold; - int max_hotlist_bssids; - int max_hotlist_ssids; - int max_significant_wifi_change_aps; - int max_bssid_history_entries; - int max_epno_ssid_crc32; - int max_epno_hidden_ssid; - int max_white_list_ssid; + int max_scan_cache_size; + int max_scan_buckets; + int max_ap_cache_per_scan; + int max_rssi_sample_size; + int max_scan_reporting_threshold; + int max_hotlist_bssids; + int max_hotlist_ssids; + int max_significant_wifi_change_aps; + int max_bssid_history_entries; + int max_epno_ssid_crc32; + int max_epno_hidden_ssid; + int max_white_list_ssid; } dhd_pno_gscan_capabilities_t; struct dhd_pno_gscan_params { @@ -483,7 +483,7 @@ int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type); void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, uint32 len, int *send_evt_bytes); + const void *data, uint32 len, int *send_evt_bytes); extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); @@ -527,9 +527,8 @@ extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, hotlist_type_t type); -extern void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - uint32 len, int *send_evt_bytes); +extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, + uint32 len, int *send_evt_bytes); extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_proto.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_proto.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_proto.h diff --git a/drivers/net/wireless/bcmdhd/dhd_rtt.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c similarity index 97% rename from drivers/net/wireless/bcmdhd/dhd_rtt.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c index f546079d7fd96e2d1ae3d62e8f7588266f5c27ec..205afce9885207182803c9b0c0bad3d2eab39b2e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_rtt.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.c @@ -448,7 +448,7 @@ rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) int rate_rspec2rate(uint32 rspec) { - int rate = -1; + int rate = 0; if (RSPEC_ISLEGACY(rspec)) { rate = 500 * (rspec & WL_RSPEC_RATE_MASK); @@ -474,7 +474,7 @@ rate_rspec2rate(uint32 rspec) ASSERT(0); } - return (rate == 0) ? -1 : rate; + return rate; } char resp_buf[WLC_IOCTL_SMLEN]; @@ -817,7 +817,7 @@ dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_inf return BCME_NOMEM; /* no TLV to pack, simply issue a set-proxd iovar */ - ret = dhd_iovar(dhd, 0, "proxd", (void *) p_proxd_iov, proxd_iovsize, 1); + ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE); #ifdef RTT_DEBUG if (ret != BCME_OK) { DHD_RTT(("error: IOVAR failed, status=%d\n", ret)); @@ -1068,7 +1068,7 @@ dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, all_tlvsize = (bufsize - buf_space_left); p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, - all_tlvsize + WL_PROXD_IOV_HDR_SIZE, 1); + all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE); if (ret != BCME_OK) { DHD_ERROR(("%s : failed to set config\n", __FUNCTION__)); } @@ -1271,7 +1271,7 @@ dhd_rtt_start(dhd_pub_t *dhd) } /* turn off mpc in case of non-associted */ if (!dhd_is_associated(dhd, NULL, NULL)) { - err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1); + err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); if (err) { DHD_ERROR(("%s : failed to set mpc\n", __FUNCTION__)); goto exit; @@ -1388,7 +1388,7 @@ exit: /* enable mpc again in case of error */ mpc = 1; rtt_status->mpc = 0; - err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1); + err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE); } } return err; @@ -1453,17 +1453,38 @@ static wifi_rate_t dhd_rtt_convert_rate_to_host(uint32 rspec) { wifi_rate_t host_rate; - if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + uint32 bandwidth; + memset(&host_rate, 0, sizeof(wifi_rate_t)); + if (RSPEC_ISLEGACY(rspec)) { host_rate.preamble = 0; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + } else if (RSPEC_ISHT(rspec)) { host_rate.preamble = 2; host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; - } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + } else if (RSPEC_ISVHT(rspec)) { host_rate.preamble = 3; host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; } - host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; + + bandwidth = RSPEC_BW(rspec); + switch (bandwidth) { + case WL_RSPEC_BW_20MHZ: + host_rate.bw = RTT_RATE_20M; + break; + case WL_RSPEC_BW_40MHZ: + host_rate.bw = RTT_RATE_40M; + break; + case WL_RSPEC_BW_80MHZ: + host_rate.bw = RTT_RATE_80M; + break; + case WL_RSPEC_BW_160MHZ: + host_rate.bw = RTT_RATE_160M; + break; + default: + host_rate.bw = RTT_RATE_20M; + break; + } + host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); return host_rate; @@ -1601,22 +1622,36 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) gfp_t kflags; bool is_new = TRUE; + DHD_RTT(("Enter %s \n", __FUNCTION__)); NULL_CHECK(dhd, "dhd is NULL", ret); + +#ifdef WL_CFG80211 rtt_status = GET_RTTSTATE(dhd); NULL_CHECK(rtt_status, "rtt_status is NULL", ret); - event_type = ntoh32_ua((void *)&event->event_type); - - if (event_type != WLC_E_PROXD) { - goto exit; - } if (RTT_IS_STOPPED(rtt_status)) { /* Ignore the Proxd event */ + DHD_RTT((" event handler rtt is stopped \n")); goto exit; } +#endif /* WL_CFG80211 */ + if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { + DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, + ntoh32_ua((void *)&event->datalen))); + ret = -EINVAL; + goto exit; + } + event_type = ntoh32_ua((void *)&event->event_type); + if (event_type != WLC_E_PROXD) { + DHD_ERROR((" failed event \n")); + ret = -EINVAL; + goto exit; + } + if (!event_data) { - DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); - return -EINVAL; + DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); + ret = -EINVAL; + goto exit; } p_event = (wl_proxd_event_t *) event_data; version = ltoh16(p_event->version); @@ -1637,6 +1672,7 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) p_loginfo = ftm_get_event_type_loginfo(event_type); if (p_loginfo == NULL) { DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); + ret = -EINVAL; goto exit; /* ignore this event */ } /* get TLVs len, skip over event header */ diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h old mode 100755 new mode 100644 similarity index 99% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h index 308f657391a53d3b99aaa007ee27157a59f9bec4..08216dbc8d08cf5b3ad6df3886abd17302aea380 --- a/drivers/net/wireless/bcmdhd_suzuran/dhd_rtt.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_rtt.h @@ -128,6 +128,14 @@ enum { RTT_BW_80 = BIT(4), RTT_BW_160 = BIT(5) }; + +enum rtt_rate_bw { + RTT_RATE_20M, + RTT_RATE_40M, + RTT_RATE_80M, + RTT_RATE_160M +}; + #define FTM_MAX_NUM_BURST_EXP 14 #define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) #define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd_sdio.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c index 3bc97304da551e0999660344602405d03ab1e0c2..179a1dfe073511a631d052f623d52710a996af5e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_sdio.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 559275 2015-05-27 05:20:28Z $ + * $Id: dhd_sdio.c 701287 2017-05-24 10:33:19Z $ */ #include @@ -4369,7 +4369,6 @@ dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) */ dhd_bus_t *bus = dhdp->bus; #ifdef BCMSDIOH_TXGLOM - char buf[256]; uint32 rxglom; int32 ret; @@ -4382,9 +4381,8 @@ dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) if (enable) { rxglom = 1; - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0, + TRUE); if (ret >= 0) bus->txglom_enable = TRUE; else { @@ -8103,7 +8101,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) } else bcmerror = BCME_SDIO_ERROR; - dhd_os_sdunlock(dhdp); + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_SDIO_ERROR; DHD_INFO(("%s called when dongle is not in reset\n", diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.c old mode 100755 new mode 100644 similarity index 100% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.c diff --git a/drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.h old mode 100755 new mode 100644 similarity index 100% rename from drivers/net/wireless/bcmdhd_suzuran/dhd_somc_custom.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_somc_custom.h diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c similarity index 98% rename from drivers/net/wireless/bcmdhd/dhd_wlfc.c rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c index e4cf02946a56b22251b6f74f5539e21c5af92e02..2b1d2731109593c55e21a44c073068d8689f04db 100644 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_wlfc.c 507166 2014-10-08 19:50:42Z $ + * $Id: dhd_wlfc.c 701287 2017-05-24 10:33:19Z $ * */ @@ -2478,7 +2478,11 @@ static void _dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) { if (info_len) { - if (info_buf && (len <= WLHOST_REORDERDATA_TOTLEN)) { + /* Check copy length to avoid buffer overrun. In case of length exceeding + * WLHOST_REORDERDATA_TOTLEN, return failure instead sending incomplete result + * of length WLHOST_REORDERDATA_TOTLEN + */ + if ((info_buf) && (len <= WLHOST_REORDERDATA_TOTLEN)) { bcopy(val, info_buf, len); *info_len = len; } @@ -2586,16 +2590,17 @@ exit: int dhd_wlfc_suspend(dhd_pub_t *dhd) { - uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ uint32 tlv = 0; + int ret; DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__)); if (!dhd->wlfc_enabled) return -1; - bcm_mkiovar("tlv", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { + ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret < 0) { DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); return -1; } @@ -2603,8 +2608,9 @@ dhd_wlfc_suspend(dhd_pub_t *dhd) if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0) return 0; tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); - bcm_mkiovar("tlv", (char *)&tlv, 4, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", __FUNCTION__, tlv)); return -1; @@ -2613,18 +2619,20 @@ dhd_wlfc_suspend(dhd_pub_t *dhd) return 0; } - int +int dhd_wlfc_resume(dhd_pub_t *dhd) { uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */ uint32 tlv = 0; + int ret; DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__)); if (!dhd->wlfc_enabled) return -1; - bcm_mkiovar("tlv", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { + ret = dhd_iovar(dhd, 0, "tlv", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); + if (ret < 0) { DHD_ERROR(("%s: failed to get bdcv2 tlv signaling\n", __FUNCTION__)); return -1; } @@ -2633,8 +2641,9 @@ dhd_wlfc_resume(dhd_pub_t *dhd) (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) return 0; tlv |= (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); - bcm_mkiovar("tlv", (char *)&tlv, 4, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, (char*)iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", __FUNCTION__, tlv)); return -1; @@ -3149,8 +3158,9 @@ dhd_wlfc_init(dhd_pub_t *dhd) */ /* enable proptxtstatus signaling by default */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, + sizeof(tlv), NULL, 0, TRUE); + if (ret < 0) { DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); } else { @@ -3163,10 +3173,8 @@ dhd_wlfc_init(dhd_pub_t *dhd) } /* query caps */ - ret = bcm_mkiovar("wlfc_mode", (char *)&mode, 4, iovbuf, sizeof(iovbuf)); - if (ret > 0) { - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); - } + ret = dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, sizeof(mode), + iovbuf, sizeof(iovbuf), FALSE); if (ret >= 0) { fw_caps = *((uint32 *)iovbuf); @@ -3181,9 +3189,10 @@ dhd_wlfc_init(dhd_pub_t *dhd) WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); } - ret = bcm_mkiovar("wlfc_mode", (char *)&mode, 4, iovbuf, sizeof(iovbuf)); - if (ret > 0) { - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + ret = dhd_iovar(dhd, 0, "wlfc_mode", (char *)&mode, + sizeof(mode), NULL, 0, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: failed to set wlfc mode, ret = %d\n", __FUNCTION__, ret)); } } @@ -3210,7 +3219,6 @@ dhd_wlfc_init(dhd_pub_t *dhd) int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) { - char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ /* enable only ampdu hostreorder here */ uint32 tlv; @@ -3224,8 +3232,8 @@ dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; /* enable proptxtstatus signaling by default */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + if (dhd_iovar(dhd, 0, "tlv", (char *)&tlv, + sizeof(tlv), NULL, 0, TRUE) < 0) { DHD_ERROR(("%s(): failed to enable/disable bdcv2 tlv signaling\n", __FUNCTION__)); } @@ -3315,8 +3323,8 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) dhd_os_wlfc_unblock(dhd); /* query ampdu hostreorder */ - bcm_mkiovar("ampdu_hostreorder", NULL, 0, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); + ret = dhd_iovar(dhd, 0, "ampdu_hostreorder", NULL, 0, + (char *)iovbuf, sizeof(iovbuf), FALSE); if (ret == BCME_OK) hostreorder = *((uint32 *)iovbuf); else { @@ -3332,8 +3340,7 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) } /* Disable proptxtstatus signaling for deinit */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + ret = dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE); if (ret == BCME_OK) { /* @@ -3963,7 +3970,6 @@ int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val) int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) { - char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */ uint32 tlv = 0; bool bChanged = FALSE; @@ -3993,8 +3999,7 @@ int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) if (bChanged) { /* select enable proptxtstatus signaling */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + if (dhd_iovar(dhd, 0, "tlv", (char *)&tlv, sizeof(tlv), NULL, 0, TRUE) < 0) { DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", __FUNCTION__, tlv)); } diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dhd_wlfc.h rename to drivers/net/wireless/bcmdhd_bcm4356/dhd_wlfc.h diff --git a/drivers/net/wireless/bcmdhd/dngl_stats.h b/drivers/net/wireless/bcmdhd_bcm4356/dngl_stats.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dngl_stats.h rename to drivers/net/wireless/bcmdhd_bcm4356/dngl_stats.h diff --git a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h similarity index 100% rename from drivers/net/wireless/bcmdhd/dngl_wlhdr.h rename to drivers/net/wireless/bcmdhd_bcm4356/dngl_wlhdr.h diff --git a/drivers/net/wireless/bcmdhd/hnd_pktpool.c b/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktpool.c similarity index 100% rename from drivers/net/wireless/bcmdhd/hnd_pktpool.c rename to drivers/net/wireless/bcmdhd_bcm4356/hnd_pktpool.c diff --git a/drivers/net/wireless/bcmdhd/hnd_pktq.c b/drivers/net/wireless/bcmdhd_bcm4356/hnd_pktq.c similarity index 100% rename from drivers/net/wireless/bcmdhd/hnd_pktq.c rename to drivers/net/wireless/bcmdhd_bcm4356/hnd_pktq.c diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c similarity index 100% rename from drivers/net/wireless/bcmdhd/hndpmu.c rename to drivers/net/wireless/bcmdhd_bcm4356/hndpmu.c diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd_bcm4356/include/Makefile similarity index 100% rename from drivers/net/wireless/bcmdhd/include/Makefile rename to drivers/net/wireless/bcmdhd_bcm4356/include/Makefile diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/aidmp.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/aidmp.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/aidmp.h diff --git a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_cfg.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcm_cfg.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcm_cfg.h diff --git a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcm_mpool_pub.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcm_mpool_pub.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmcdc.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmcdc.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmcdc.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdefs.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmdefs.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmdefs.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmdevs.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmdevs.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmdevs.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmendian.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmendian.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmendian.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmmsgbuf.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmmsgbuf.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmnvram.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmnvram.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmnvram.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcie.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcie.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmpcie.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcie.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcispi.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmpcispi.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmpcispi.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmperf.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmperf.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmperf.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdbus.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsdbus.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdbus.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsdh.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh_sdmmc.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdh_sdmmc.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdpcm.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsdpcm.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdpcm.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdspi.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsdspi.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdspi.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdstd.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsdstd.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsdstd.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspi.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmspi.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmspi.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmspibrcm.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmspibrcm.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmspibrcm.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_fmt.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_fmt.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_tbl.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmsrom_tbl.h diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd_bcm4356/include/bcmutils.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/bcmutils.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/bcmutils.h diff --git a/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_bcm4356/include/brcm_nl80211.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/brcm_nl80211.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/brcm_nl80211.h diff --git a/drivers/net/wireless/bcmdhd/include/dbus.h b/drivers/net/wireless/bcmdhd_bcm4356/include/dbus.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/dbus.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/dbus.h diff --git a/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/devctrl_if/wlioctl_defs.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/devctrl_if/wlioctl_defs.h diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/dhdioctl.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/dhdioctl.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/dhdioctl.h diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h similarity index 89% rename from drivers/net/wireless/bcmdhd/include/epivers.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h index 5d7e6a0d633bd7ebc8e29a5a93997bfe64e59d7f..8624621913d937370b1e916c9c22887af9eca09b 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/epivers.h @@ -30,19 +30,19 @@ #define EPI_MINOR_VERSION 71 -#define EPI_RC_NUMBER 21 +#define EPI_RC_NUMBER 26 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 71, 21, 0 +#define EPI_VERSION 1, 71, 26, 0 -#define EPI_VERSION_NUM 0x01471500 +#define EPI_VERSION_NUM 0x01471a00 -#define EPI_VERSION_DEV 1.71.21 +#define EPI_VERSION_DEV 1.71.26 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.71.21 (r)" +#define EPI_VERSION_STR "1.71.26 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_armtrap.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/hnd_armtrap.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/hnd_armtrap.h diff --git a/drivers/net/wireless/bcmdhd/include/hnd_cons.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_cons.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/hnd_cons.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/hnd_cons.h diff --git a/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktpool.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/hnd_pktpool.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktpool.h diff --git a/drivers/net/wireless/bcmdhd/include/hnd_pktq.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktq.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/hnd_pktq.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/hnd_pktq.h diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hndpmu.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/hndpmu.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/hndpmu.h diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/hndsoc.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/hndsoc.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/hndsoc.h diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h similarity index 99% rename from drivers/net/wireless/bcmdhd/include/linux_osl.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h index 99e8dffe35e7c5feb46edaace7bc3c3f06947fb9..3ce18fa61bf70298edca5981c71f3150deebfe61 100644 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/linux_osl.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.h 614089 2016-01-21 02:43:09Z $ + * $Id: linux_osl.h 676007 2016-12-20 02:31:31Z $ */ #ifndef _linux_osl_h_ @@ -243,7 +243,7 @@ extern int osl_error(int bcmerror); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) #define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) #else -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define OSL_SYSUPTIME() ((uint32)jiffies * msecs_to_jiffies(1)) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ #define printf(fmt, args...) printk(fmt , ## args) #include /* for vsn/printf's */ diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd_bcm4356/include/linuxver.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/linuxver.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/linuxver.h diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd_bcm4356/include/miniopt.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/miniopt.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/miniopt.h diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd_bcm4356/include/msgtrace.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/msgtrace.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/msgtrace.h diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/osl.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/osl.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/osl.h diff --git a/drivers/net/wireless/bcmdhd/include/osl_decl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/osl_decl.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/osl_decl.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/osl_decl.h diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_end.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/packed_section_end.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_end.h diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_start.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/packed_section_start.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/packed_section_start.h diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd_bcm4356/include/pcicfg.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/pcicfg.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/pcicfg.h diff --git a/drivers/net/wireless/bcmdhd/include/pcie_core.h b/drivers/net/wireless/bcmdhd_bcm4356/include/pcie_core.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/pcie_core.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/pcie_core.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/802.11.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11_bta.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11_bta.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11e.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/802.11e.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.11e.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.1d.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/802.1d.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.1d.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.3.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/802.3.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/802.3.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmdhcp.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmdhcp.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h similarity index 98% rename from drivers/net/wireless/bcmdhd/include/proto/bcmeth.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h index 90067b20769494d9fcc448ea2efba2b1f3c45e7f..2657d2fdf5ab5e3ebbf4dbaa397d8998041deed3 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmeth.h @@ -93,7 +93,6 @@ #define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 #define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 -#define BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD 2 /* These fields are stored in network order */ typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h similarity index 99% rename from drivers/net/wireless/bcmdhd/include/proto/bcmevent.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h index e3801f89d05303b3ad48a7a3df8f618aaf6fef77..c0894a097cb976f2b42c544e0bf72c40362dd4bf 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmevent.h @@ -224,7 +224,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */ #define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ #define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ -/* 135 was legacy entry for WLC_E_PFN_SWC can be reused */ +#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */ #define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ #define WLC_E_RMC_EVENT 139 /* RMC event */ #define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmip.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/bcmip.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmip.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmipv6.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmipv6.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmtcp.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmtcp.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmudp.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/bcmudp.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bcmudp.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/bt_amp_hci.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/bt_amp_hci.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/eapol.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/eapol.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/eapol.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/ethernet.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/ethernet.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/ethernet.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/nan.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/nan.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/nan.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/nan.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/p2p.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/p2p.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/p2p.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/sdspi.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/sdspi.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/sdspi.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/vlan.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/vlan.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/vlan.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wpa.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/wpa.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/wpa.h diff --git a/drivers/net/wireless/bcmdhd/include/proto/wps.h b/drivers/net/wireless/bcmdhd_bcm4356/include/proto/wps.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/proto/wps.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/proto/wps.h diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbchipc.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbchipc.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbchipc.h diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbconfig.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbconfig.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbconfig.h diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbhnddma.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbhnddma.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbhnddma.h diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbpcmcia.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbpcmcia.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbpcmcia.h diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdio.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbsdio.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbsdio.h diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsdpcmdev.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbsdpcmdev.h diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sbsocram.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sbsocram.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sbsocram.h diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sdio.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sdio.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sdio.h diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sdioh.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sdioh.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sdioh.h diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd_bcm4356/include/sdiovar.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/sdiovar.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/sdiovar.h diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd_bcm4356/include/siutils.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/siutils.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/siutils.h diff --git a/drivers/net/wireless/bcmdhd/include/spid.h b/drivers/net/wireless/bcmdhd_bcm4356/include/spid.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/spid.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/spid.h diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd_bcm4356/include/trxhdr.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/trxhdr.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/trxhdr.h diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd_bcm4356/include/typedefs.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/typedefs.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/typedefs.h diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_bcm4356/include/wlfc_proto.h similarity index 100% rename from drivers/net/wireless/bcmdhd/include/wlfc_proto.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/wlfc_proto.h diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h similarity index 99% rename from drivers/net/wireless/bcmdhd/include/wlioctl.h rename to drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h index 65469208f67a8a4346a9501bc467b0f929b24499..aa71bca48928f4c7a1f6d4455f2abc77ed861c9b 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/include/wlioctl.h @@ -2722,6 +2722,12 @@ typedef struct wl_pfn_bssid { uint16 flags; } wl_pfn_bssid_t; +typedef struct wl_pfn_significant_bssid { + struct ether_addr macaddr; + int8 rssi_low_threshold; + int8 rssi_high_threshold; +} wl_pfn_significant_bssid_t; + #define WL_PFN_SUPPRESSFOUND_MASK 0x08 #define WL_PFN_SUPPRESSLOST_MASK 0x10 #define WL_PFN_RSSI_MASK 0xff00 diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd_bcm4356/linux_osl.c similarity index 100% rename from drivers/net/wireless/bcmdhd/linux_osl.c rename to drivers/net/wireless/bcmdhd_bcm4356/linux_osl.c diff --git a/drivers/net/wireless/bcmdhd/pcie_core.c b/drivers/net/wireless/bcmdhd_bcm4356/pcie_core.c similarity index 100% rename from drivers/net/wireless/bcmdhd/pcie_core.c rename to drivers/net/wireless/bcmdhd_bcm4356/pcie_core.c diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd_bcm4356/sbutils.c similarity index 100% rename from drivers/net/wireless/bcmdhd/sbutils.c rename to drivers/net/wireless/bcmdhd_bcm4356/sbutils.c diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd_bcm4356/siutils.c similarity index 99% rename from drivers/net/wireless/bcmdhd/siutils.c rename to drivers/net/wireless/bcmdhd_bcm4356/siutils.c index 6ae7c4c323d2a42168b449f8b3e46e3c17208692..7cbec760875735720f8bb606980e9717a3cedb14 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/siutils.c @@ -495,11 +495,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } sih->bustype = bustype; +#ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); return NULL; } +#endif /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { diff --git a/drivers/net/wireless/bcmdhd/siutils_priv.h b/drivers/net/wireless/bcmdhd_bcm4356/siutils_priv.h similarity index 100% rename from drivers/net/wireless/bcmdhd/siutils_priv.h rename to drivers/net/wireless/bcmdhd_bcm4356/siutils_priv.h diff --git a/drivers/net/wireless/bcmdhd/uamp_api.h b/drivers/net/wireless/bcmdhd_bcm4356/uamp_api.h similarity index 100% rename from drivers/net/wireless/bcmdhd/uamp_api.h rename to drivers/net/wireless/bcmdhd_bcm4356/uamp_api.h diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c similarity index 97% rename from drivers/net/wireless/bcmdhd/wl_android.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_android.c index d02169804c49bd5f8d3525da9f1a6fba3e9ba158..e58496de3b4eba7906d35a616e102cac6655d599 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 675132 2016-12-14 09:13:20Z $ + * $Id: wl_android.c 701287 2017-05-24 10:33:19Z $ */ #include @@ -573,7 +573,7 @@ int wl_android_get_assoclist(struct net_device *dev, char *command, int total_le assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); - error = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), false); + error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf)); if (error) return -1; @@ -853,7 +853,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t str_ptr += sizeof(cmd_tlv_t); tlv_size_left -= sizeof(cmd_tlv_t); - if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, + if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local, MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); goto exit_proc; @@ -1006,21 +1006,21 @@ wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist * struct maclist *assoc_maclist = (struct maclist *)mac_buf; /* set filtering mode */ - if ((ret = wldev_ioctl(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) { + if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode))) != 0) { DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); return ret; } if (macmode != MACLIST_MODE_DISABLED) { /* set the MAC filter list */ - if ((ret = wldev_ioctl(dev, WLC_SET_MACLIST, maclist, - sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) { + if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist, + sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) { DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); return ret; } /* get the current list of associated STAs */ assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; - if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, - sizeof(mac_buf), false)) != 0) { + if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, + sizeof(mac_buf))) != 0) { DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); return ret; } @@ -1049,9 +1049,9 @@ wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist * scbval.val = htod32(1); memcpy(&scbval.ea, &assoc_maclist->ea[i], ETHER_ADDR_LEN); - if ((ret = wldev_ioctl(dev, + if ((ret = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, - &scbval, sizeof(scb_val_t), true)) != 0) + &scbval, sizeof(scb_val_t))) != 0) DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", __FUNCTION__, ret)); } @@ -1234,7 +1234,6 @@ wl_chanim_stats(struct net_device *dev, u8 *chan_idle) chanim_stats_t *stats; memset(¶m, 0, sizeof(param)); - memset(result, 0, sizeof(result)); param.buflen = htod32(sizeof(wl_chanim_stats_t)); param.count = htod32(WL_CHANIM_COUNT_ONE); @@ -1314,7 +1313,6 @@ wl_android_get_connection_stats(struct net_device *dev, char *command, int total WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); goto error; } - memset(if_stats, 0, sizeof(*if_stats)); ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, (char *)if_stats, sizeof(*if_stats), NULL); @@ -1583,8 +1581,8 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) uint8 buf[MAX_BUF_SIZE]; uint8 *pref = buf; char *pcmd; - uint num_ucipher_suites; - uint num_akm_suites; + int num_ucipher_suites = 0; + int num_akm_suites = 0; wpa_suite_t ucipher_suites[MAX_NUM_SUITES]; wpa_suite_t akm_suites[MAX_NUM_SUITES]; int num_tuples = 0; @@ -1598,9 +1596,10 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) num_akm_suites = simple_strtoul(pcmd, NULL, 16); if (num_akm_suites > MAX_NUM_SUITES) { - WL_ERR(("wrong num_akm_suites:%d.\n", num_akm_suites)); - return BCME_ERROR; + DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites)); + return -1; } + /* Increment for number of AKM suites field + space */ pcmd += 3; total_len_left -= 3; @@ -1627,8 +1626,8 @@ wl_android_set_roampref(struct net_device *dev, char *command, int total_len) total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); if (num_ucipher_suites > MAX_NUM_SUITES) { - WL_ERR(("wrong num_ucipher_suites:%d.\n", num_ucipher_suites)); - return BCME_ERROR; + DHD_ERROR(("too many UCIPHER suites = %d\n", num_ucipher_suites)); + return -1; } /* Increment for number of cipher suites field + space */ pcmd += 3; @@ -1743,13 +1742,13 @@ wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_ ret = -ENOMEM; goto error; } - ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false); + ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len); if (ret) { DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, config->ioctl)); goto error; } - ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true); + ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len); if (ret) { DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, config->iovar, config->param)); @@ -1785,8 +1784,8 @@ wl_android_iolist_resume(struct net_device *dev, struct list_head *head) config->param); } else { if (!ret) - ret = wldev_ioctl(dev, config->ioctl + 1, - config->arg, config->len, true); + ret = wldev_ioctl_set(dev, config->ioctl + 1, + config->arg, config->len); if (config->ioctl + 1 == WLC_SET_PM) wl_cfg80211_update_power_mode(dev); kfree(config->arg); @@ -1799,7 +1798,7 @@ wl_android_iolist_resume(struct net_device *dev, struct list_head *head) static int wl_android_set_miracast(struct net_device *dev, char *command, int total_len) { - int mode, val; + int mode, val = 0; int ret = 0; struct io_cfg config; #ifdef CHANGE_SCAN_TIME @@ -1825,7 +1824,7 @@ wl_android_set_miracast(struct net_device *dev, char *command, int total_len) /* setting mchan_algo to platform specific value */ config.iovar = "mchan_algo"; - ret = wldev_ioctl(dev, WLC_GET_BCNPRD, &val, sizeof(int), false); + ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int)); if (!ret && val > 100) { config.param = 0; DHD_ERROR(("%s: Connected station's beacon interval: " @@ -1868,7 +1867,7 @@ wl_android_set_miracast(struct net_device *dev, char *command, int total_len) } /* tunr off pm */ - ret = wldev_ioctl(dev, WLC_GET_PM, &val, sizeof(val), false); + ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val)); if (ret) { goto resume; } @@ -2296,14 +2295,10 @@ int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) { - char buf[256]; - const char *str; wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; + int ret; uint period_msec = 0; + char *buf; if (extra == NULL) { @@ -2319,36 +2314,27 @@ int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[ str_len ] = '\0'; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); mkeep_alive_pkt.period_msec = period_msec; - buf_len = str_len + 1; mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); /* Setup keep alive zero for null packet generation */ mkeep_alive_pkt.keep_alive_id = 0; mkeep_alive_pkt.len_bytes = 0; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - if ((res = wldev_ioctl(dev, WLC_SET_VAR, buf, buf_len, TRUE)) < 0) - { - DHD_ERROR(("%s:keep_alive set failed. res[%d]\n", __FUNCTION__, res)); - } - else - { - DHD_ERROR(("%s:keep_alive set ok. res[%d]\n", __FUNCTION__, res)); + buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + if (!buf) { + DHD_ERROR(("%s: buffer alloc failed\n", __FUNCTION__)); + return BCME_NOMEM; } - return res; + ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt, + WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL); + if (ret < 0) + DHD_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret)); + else + DHD_TRACE(("%s:keep_alive set ok\n", __FUNCTION__)); + kfree(buf); + return ret; } @@ -2424,9 +2410,10 @@ static int wl_android_get_link_status(struct net_device *dev, char *command, int datalen = sizeof(uint32) + sizeof(wl_bss_info_t); char buf[datalen]; + memset(buf, 0, datalen); /* get BSS information */ *(u32 *) buf = htod32(datalen); - error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void *)buf, datalen, false); + error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen); if (unlikely(error)) { WL_ERR(("Could not get bss info %d\n", error)); return -1; @@ -2574,11 +2561,6 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) goto exit; } - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto exit; - } - #ifdef CONFIG_COMPAT if (is_compat_task()) { compat_android_wifi_priv_cmd compat_priv_cmd; diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_android.h similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_android.h rename to drivers/net/wireless/bcmdhd_bcm4356/wl_android.h diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c similarity index 97% rename from drivers/net/wireless/bcmdhd/wl_cfg80211.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c index 5e38c7f33f972e02ba2cbd24f2034b2477416d42..7a806d96a41ac91d8ea8c3a52f4e7c7e0f974cf2 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 676010 2016-12-20 03:01:18Z $ + * $Id: wl_cfg80211.c 718504 2017-08-31 02:38:08Z $ */ /* */ #include @@ -377,8 +377,9 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); -static s32 wl_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *ndev, u8* mac_addr); +static s32 wl_cfg80211_del_station( + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params); static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -1282,7 +1283,7 @@ s32 wl_set_tx_power(struct net_device *dev, /* Make sure radio is off or on as far as software is concerned */ disable = WL_RADIO_SW_DISABLE << 16; disable = htod32(disable); - err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true); + err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable)); if (unlikely(err)) { WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); return err; @@ -1338,8 +1339,10 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); struct ether_addr bssid; struct wl_bss_info *bss = NULL; + char *buf; - if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { + memset(&bssid, 0, sizeof(bssid)); + if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) { /* STA interface is not associated. So start the new interface on a temp * channel . Later proper channel will be applied by the above framework * via set_channel (cfg80211 API). @@ -1348,19 +1351,25 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); } + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!buf) { + WL_ERR(("buf alloc failed. use temp channel\n")); + return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); + } - *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX); - if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, cfg->extra_buf, - WL_EXTRA_BUF_MAX, false))) { + *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf, + WL_EXTRA_BUF_MAX))) { WL_ERR(("Failed to get associated bss info, use temp channel \n")); chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); } else { - bss = (struct wl_bss_info *) (cfg->extra_buf + 4); + bss = (wl_bss_info_t *) (buf + 4); chspec = bss->chanspec; WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); } + kfree(buf); return chspec; } @@ -1510,7 +1519,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && dhd->op_mode != DHD_FLAG_IBSS_MODE) { dhd_wlfc_init(dhd); - err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true); + err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32)); if (err < 0) WL_ERR(("WLC_UP return err:%d\n", err)); } @@ -1882,7 +1891,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, if (ibss) { infra = 0; wl_set_mode_by_netdev(cfg, ndev, mode); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true); + err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32)); if (err < 0) { WL_ERR(("SET Adhoc error %d\n", err)); return -EINVAL; @@ -2212,7 +2221,7 @@ wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) memset(valid_chan_list, 0, size); list = (wl_uint32_list_t *)(void *) valid_chan_list; list->count = htod32(WL_NUMCHANNELS); - err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); + err = wldev_ioctl_get(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size); if (err != 0) { WL_ERR(("get channels failed with %d\n", err)); } @@ -2373,10 +2382,8 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { list = (wl_uint32_list_t *) chan_buf; n_valid_chan = dtoh32(list->count); - if (n_valid_chan > WL_NUMCHANNELS) { - WL_ERR(("wrong n_valid_chan:%d\n", - n_valid_chan)); + WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan)); kfree(default_chan_list); err = -EINVAL; goto exit; @@ -2417,12 +2424,13 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, /* allows only supported channel on * current reguatory */ - if (n_nodfs >= num_chans) + if (n_nodfs >= num_chans) { break; - - if (channel == (dtoh32(list->element[j]))) + } + if (channel == (dtoh32(list->element[j]))) { default_chan_list[n_nodfs++] = channel; + } } } @@ -2488,7 +2496,7 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd s32 err = BCME_OK; s32 passive_scan; s32 passive_scan_time; - s32 passive_scan_time_org; + s32 passive_scan_time_org = 0; wl_scan_results_t *results; WL_SCAN(("Enter \n")); mutex_lock(&cfg->usr_sync); @@ -2502,8 +2510,8 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd cfg->escan_info.wiphy = wiphy; cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING; passive_scan = cfg->active_scan ? 0 : 1; - err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), true); + err = wldev_ioctl_set(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); goto exit; @@ -2511,8 +2519,8 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd if (passive_channel_skip) { - err = wldev_ioctl(ndev, WLC_GET_SCAN_PASSIVE_TIME, - &passive_scan_time_org, sizeof(passive_scan_time_org), false); + err = wldev_ioctl_get(ndev, WLC_GET_SCAN_PASSIVE_TIME, + &passive_scan_time_org, sizeof(passive_scan_time_org)); if (unlikely(err)) { WL_ERR(("== error (%d)\n", err)); goto exit; @@ -2521,8 +2529,8 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org)); passive_scan_time = 0; - err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, - &passive_scan_time, sizeof(passive_scan_time), true); + err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME, + &passive_scan_time, sizeof(passive_scan_time)); if (unlikely(err)) { WL_ERR(("== error (%d)\n", err)); goto exit; @@ -2535,8 +2543,8 @@ wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *nd err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START); if (passive_channel_skip) { - err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, - &passive_scan_time_org, sizeof(passive_scan_time_org), true); + err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME, + &passive_scan_time_org, sizeof(passive_scan_time_org)); if (unlikely(err)) { WL_ERR(("== error (%d)\n", err)); goto exit; @@ -2774,8 +2782,8 @@ scan_out: wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev))); bzero(&bssid, sizeof(bssid)); - if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, - &bssid, ETHER_ADDR_LEN, false)) == 0) + if ((ret = wldev_ioctl_get(ndev, WLC_GET_BSSID, + &bssid, ETHER_ADDR_LEN)) == 0) WL_ERR(("FW is connected with " MACDBG "/n", MAC2STRDBG(bssid.octet))); else @@ -2859,7 +2867,7 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); retry = htod32(retry); - err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); + err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry)); if (unlikely(err)) { WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); return err; @@ -2925,14 +2933,15 @@ channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u3 WL_ERR(("buf memory alloc failed\n")); goto exit; } - list = (wl_uint32_list_t *)(void *)buf; - list->count = htod32(WL_NUMCHANSPECS); + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync); if (err != BCME_OK) { WL_ERR(("get chanspecs failed with %d\n", err)); goto exit; } + + list = (wl_uint32_list_t *)(void *)buf; for (i = 0; i < dtoh32(list->count); i++) { c = dtoh32(list->element[i]); if (channel <= CH_MAX_2G_CHANNEL) { @@ -3572,8 +3581,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, join_params.ssid.SSID_len = htod32(params->ssid_len); if (params->bssid) { memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); - err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, - ETHER_ADDR_LEN, true); + err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, + ETHER_ADDR_LEN); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -3585,8 +3594,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { scan_suppress = TRUE; /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */ - err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &scan_suppress, sizeof(int), true); + err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int)); if (unlikely(err)) { WL_ERR(("Scan Suppress Setting Failed (%d)\n", err)); return err; @@ -3611,7 +3620,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, return err; } #ifdef WLAIBSS_PS - err = wldev_ioctl(dev, WLC_SET_ATIM, &atim, sizeof(int), true); + err = wldev_ioctl_set(dev, WLC_SET_ATIM, &atim, sizeof(int)); if (unlikely(err)) { WL_ERR(("Enable custom IBSS ATIM mode failed (%d)\n", err)); return err; @@ -3619,8 +3628,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, #endif /* WLAIBSS_PS */ #endif /* WLAIBSS */ - err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true); + err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, + join_params_size); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -3629,8 +3638,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { scan_suppress = FALSE; /* Reset the SCAN SUPPRESS Flag */ - err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &scan_suppress, sizeof(int), true); + err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int)); if (unlikely(err)) { WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err)); return err; @@ -3660,8 +3669,8 @@ static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) wl_set_drv_status(cfg, DISCONNECTING, dev); scbval.val = 0; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); if (unlikely(err)) { wl_clr_drv_status(cfg, DISCONNECTING, dev); WL_ERR(("error(%d)\n", err)); @@ -4281,7 +4290,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, #endif bzero(&bssid, sizeof(bssid)); if (!wl_get_drv_status(cfg, CONNECTED, dev)&& - (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { + (ret = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) == 0) { if (!ETHER_ISNULLADDR(&bssid)) { scb_val_t scbval; wl_set_drv_status(cfg, DISCONNECTING, dev); @@ -4291,8 +4300,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", MAC2STRDBG(bssid.octet))); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); if (unlikely(err)) { wl_clr_drv_status(cfg, DISCONNECTING, dev); WL_ERR(("error (%d)\n", err)); @@ -4378,8 +4387,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (is_roamtrig_reset && is_roam_env_ok) { roam_trigger[0] = WL_AUTO_ROAM_TRIGGER; roam_trigger[1] = WLC_BAND_ALL; - err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger), true); + err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger)); if (unlikely(err)) { WL_ERR((" failed to restore roam_trigger for auto env" " detection\n")); @@ -4543,7 +4552,7 @@ set_ssid: join_params.ssid.SSID_len)); } wl_set_drv_status(cfg, CONNECTING, dev); - err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); + err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size); if (err) { WL_ERR(("error (%d)\n", err)); wl_clr_drv_status(cfg, CONNECTING, dev); @@ -4590,8 +4599,8 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, scbval.val = reason_code; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); - err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); if (unlikely(err)) { wl_clr_drv_status(cfg, DISCONNECTING, dev); WL_ERR(("error (%d)\n", err)); @@ -4704,8 +4713,8 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, /* Just select a new current key */ index = (u32) key_idx; index = htod32(index); - err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, - sizeof(index), true); + err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index, + sizeof(index)); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -4948,7 +4957,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, bcopy(keystring, pmk.key, len); pmk.flags = htod16(WSEC_PASSPHRASE); - err = wldev_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk), true); + err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (err) return err; } break; @@ -5155,7 +5164,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, if (cfg->roam_offload) { struct ether_addr bssid; - err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); if (err) { WL_ERR(("Failed to get current BSSID\n")); } else { @@ -5184,7 +5194,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } /* Report the current tx rate */ - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); + rate = 0; + err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate)); if (err) { WL_ERR(("Could not get rate (%d)\n", err)); } else { @@ -5214,8 +5225,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, memset(&scb_val, 0, sizeof(scb_val)); scb_val.val = 0; - err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), false); + err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t)); if (err) { WL_ERR(("Could not get rssi (%d)\n", err)); goto get_station_err; @@ -5224,8 +5235,9 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = rssi; WL_DBG(("RSSI %d dBm\n", rssi)); - err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, - sizeof(pktcnt), false); + memset(&pktcnt, 0, sizeof(pktcnt)); + err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt, + sizeof(pktcnt)); if (!err) { sinfo->filled |= (STATION_INFO_RX_PACKETS | STATION_INFO_RX_DROP_MISC | @@ -5279,7 +5291,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, } pm = htod32(pm); WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); - err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); + err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); if (unlikely(err)) { if (err == -ENODEV) WL_DBG(("net_device is not ready yet\n")); @@ -5295,7 +5307,7 @@ void wl_cfg80211_update_power_mode(struct net_device *dev) { int err, pm = -1; - err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), true); + err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm)); if (err) WL_ERR(("%s:error (%d)\n", __FUNCTION__, err)); else if (pm != -1 && dev->ieee80211_ptr) @@ -6284,8 +6296,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, if (len > (ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN)) { WL_ERR(("bad length:%zu\n", len)); - return BCME_BADARG; + return BCME_BADLEN; } + dev = cfgdev_to_wlc_ndev(cfgdev, cfg); if (!dev) { @@ -6331,7 +6344,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, s32 ie_len = len - ie_offset; if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(cfg, dev, bssidx, + wl_cfgp2p_set_management_ie(cfg, dev, bssidx, VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -6344,8 +6357,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, if (!bcmp((const uint8 *)BSSID_BROADCAST, (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(dev, WLC_GET_ASSOCLIST, - assoc_maclist, sizeof(mac_buf), false); + err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, + assoc_maclist, sizeof(mac_buf)); if (err < 0) WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); else @@ -6353,8 +6366,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, } memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); scb_val.val = mgmt->u.disassoc.reason_code; - err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); + err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t)); if (err < 0) WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); WL_ERR(("Disconnect STA : %s scb_val.val %d\n", @@ -6536,7 +6549,7 @@ wl_cfg80211_change_bss(struct wiphy *wiphy, if (nmode == nmode_prev) { nmode = -1; } - err = wldev_ioctl(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev), 0); + err = wldev_ioctl_get(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev)); if (unlikely(err)) { WL_ERR(("error reading gmode (%d)\n", err)); } @@ -6548,7 +6561,7 @@ wl_cfg80211_change_bss(struct wiphy *wiphy, ((gmode > -1) || (nmode > -1))) { s32 val = 0; - err = wldev_ioctl(dev, WLC_DOWN, &val, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32)); if (unlikely(err)) WL_ERR(("WLC_DOWN command failed:[%d]\n", err)); @@ -6559,14 +6572,14 @@ wl_cfg80211_change_bss(struct wiphy *wiphy, } if (gmode > -1) { - err = wldev_ioctl(dev, WLC_SET_GMODE, &gmode, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_SET_GMODE, &gmode, sizeof(s32)); if (unlikely(err)) WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n", gmode, err)); } val = 0; - err = wldev_ioctl(dev, WLC_UP, &val, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32)); if (unlikely(err)) WL_ERR(("WLC_UP command failed:err[%d]\n", err)); @@ -6673,8 +6686,8 @@ set_channel: fw_chspec)) == BCME_BADCHAN) { if (bw == WL_CHANSPEC_BW_80) goto change_bw; - err = wldev_ioctl(dev, WLC_SET_CHANNEL, - &_chan, sizeof(_chan), true); + err = wldev_ioctl_set(dev, WLC_SET_CHANNEL, + &_chan, sizeof(_chan)); if (err < 0) { WL_ERR(("WLC_SET_CHANNEL error %d" "chip may not be supporting this channel\n", err)); @@ -7186,16 +7199,16 @@ static s32 wl_cfg80211_bcn_set_params( info->beacon_interval, info->dtim_period)); if (info->beacon_interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->beacon_interval, sizeof(s32), true)) < 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, + &info->beacon_interval, sizeof(s32))) < 0) { WL_ERR(("Beacon Interval Set Error, %d\n", err)); return err; } } if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32))) < 0) { WL_ERR(("DTIM Interval Set Error, %d\n", err)); return err; } @@ -7286,7 +7299,7 @@ wl_cfg80211_bcn_bringup_ap( is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); if (!is_bssup && (ies->wpa2_ie != NULL)) { - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32)); if (err < 0) { WL_ERR(("SET INFRA error %d\n", err)); goto exit; @@ -7312,30 +7325,30 @@ wl_cfg80211_bcn_bringup_ap( } else if ((dev_role == NL80211_IFTYPE_AP) && (wl_get_drv_status(cfg, AP_CREATING, dev))) { /* Device role SoftAP */ - err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32)); if (err < 0) { WL_ERR(("WLC_DOWN error %d\n", err)); goto exit; } - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32)); if (err < 0) { WL_ERR(("SET INFRA error %d\n", err)); goto exit; } - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) { WL_ERR(("setting AP mode failed %d \n", err)); goto exit; } #ifdef DISABLE_11H_SOFTAP - err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, - &spect, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, + &spect, sizeof(s32)); if (err < 0) { WL_ERR(("SET SPECT_MANAGMENT error %d\n", err)); goto exit; } #endif /* DISABLE_11H_SOFTAP */ - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32)); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); goto exit; @@ -7351,8 +7364,8 @@ wl_cfg80211_bcn_bringup_ap( join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); /* create softap */ - if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - join_params_size, true)) == 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, + join_params_size)) == 0) { WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); wl_clr_drv_status(cfg, AP_CREATING, dev); wl_set_drv_status(cfg, AP_CREATED, dev); @@ -7531,9 +7544,8 @@ static s32 wl_cfg80211_hostapd_sec( 2, 0)) static s32 wl_cfg80211_del_station( - struct wiphy *wiphy, - struct net_device *ndev, - u8* mac_addr) + struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) { struct net_device *dev; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -7545,6 +7557,8 @@ wl_cfg80211_del_station( struct maclist *assoc_maclist = (struct maclist *)mac_buf; int num_associated = 0; + const u8 *mac_addr = params->mac; + WL_DBG(("Entry\n")); if (mac_addr == NULL) { WL_DBG(("mac_addr is NULL ignore it\n")); @@ -7564,8 +7578,8 @@ wl_cfg80211_del_station( } assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, - assoc_maclist, sizeof(mac_buf), false); + err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST, + assoc_maclist, sizeof(mac_buf)); if (err < 0) WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); else @@ -7573,8 +7587,8 @@ wl_cfg80211_del_station( memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); scb_val.val = DOT11_RC_DEAUTH_LEAVING; - err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); + err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t)); if (err < 0) WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); WL_ERR(("Disconnect STA : %s scb_val.val %d\n", @@ -7607,13 +7621,13 @@ wl_cfg80211_change_station( } if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) { - err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true); + err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN); if (err) WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err)); return err; } - err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true); + err = wldev_ioctl_set(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN); if (err) WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); return err; @@ -7766,19 +7780,19 @@ wl_cfg80211_stop_ap( /* SoftAp on primary Interface. * Shut down AP and turn on MPC */ - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) { WL_ERR(("setting AP mode failed %d \n", err)); err = -ENOTSUPP; goto exit; } - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32)); if (err < 0) { WL_ERR(("SET INFRA error %d\n", err)); err = -ENOTSUPP; goto exit; } - err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); + err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32)); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); err = -EINVAL; @@ -7983,15 +7997,15 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, /* Set BI and DTIM period */ if (info->interval) { - if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, - &info->interval, sizeof(s32), true)) < 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, + &info->interval, sizeof(s32))) < 0) { WL_ERR(("Beacon Interval Set Error, %d\n", err)); return err; } } if (info->dtim_period) { - if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, - &info->dtim_period, sizeof(s32), true)) < 0) { + if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, + &info->dtim_period, sizeof(s32))) < 0) { WL_ERR(("DTIM Interval Set Error, %d\n", err)); return err; } @@ -8289,7 +8303,7 @@ static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, /* Set interface up, explicitly. */ val = 1; - err = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); + err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val); if (err < 0) { WL_ERR(("set interface up failed, error = %d\n", err)); } @@ -8298,8 +8312,9 @@ static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, /* Get noise value */ retry = IOCTL_RETRY_COUNT; while (retry--) { - err = wldev_ioctl(ndev, WLC_GET_PHY_NOISE, &noise, - sizeof(noise), false); + noise = 0; + err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise, + sizeof(noise)); if (err >= 0) { break; } @@ -8912,7 +8927,8 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + memset(&bssid, 0, sizeof(bssid)); + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); switch (event) { case WLC_E_ASSOC_IND: fc = FC_ASSOC_REQ; @@ -8933,7 +8949,8 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, fc = 0; goto exit; } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { + memset(&ci, 0, sizeof(ci)); + if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) { kfree(body); return err; } @@ -9132,6 +9149,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, s32 err = 0; u32 event = ntoh32(e->event_type); +#ifdef DHD_ENABLE_DISC_TIME_LOG + struct timeval tv_now; + do_gettimeofday(&tv_now); +#endif /* DHD_ENABLE_DISC_TIME_LOG */ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { @@ -9172,6 +9193,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; +#ifdef DHD_ENABLE_DISC_TIME_LOG + printk("KERN_ERR [Log]%s: current time=%lu\n", __FUNCTION__, + (unsigned long int) tv_now.tv_sec*1000000+tv_now.tv_usec); +#endif /* DHD_ENABLE_DISC_TIME_LOG */ printk("link down if %s may call cfg80211_disconnected. " "event : %d, reason=%d from " MACDBG "\n", ndev->name, event, ntoh32(e->reason), @@ -9192,8 +9217,8 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); - err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); + err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); if (err < 0) { WL_ERR(("WLC_DISASSOC error %d\n", err)); err = 0; @@ -9373,6 +9398,32 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.req_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.req_len > 0) && + (assoc_info.req_len < (sizeof(struct dot11_assoc_req) + + ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? + ETHER_ADDR_LEN : 0)))) { + err = BCME_BADLEN; + goto exit; + } + if (assoc_info.resp_len > + (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if ((assoc_info.resp_len > 0) && + (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) { + err = BCME_BADLEN; + goto exit; + } + if (conn_info->req_ie_len) { conn_info->req_ie_len = 0; bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); @@ -9381,48 +9432,42 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) conn_info->resp_ie_len = 0; bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } + if (assoc_info.req_len) { - err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); - return err; + goto exit; } - conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + conn_info->req_ie_len = assoc_info.req_len - + sizeof(struct dot11_assoc_req); if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - if (conn_info->req_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->req_ie_len, MAX_REQ_LINE)); - return err; - } - } else { - conn_info->req_ie_len = 0; + memcpy(conn_info->req_ie, cfg->extra_buf, + conn_info->req_ie_len); } + if (assoc_info.resp_len) { - err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf, - WL_ASSOC_INFO_MAX, NULL); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, + cfg->extra_buf, WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); - return err; - } - conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - if (conn_info->resp_ie_len <= MAX_REQ_LINE) - memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); - else { - WL_ERR(("IE size %d above max %d size \n", - conn_info->resp_ie_len, MAX_REQ_LINE)); - return err; + goto exit; } - } else { - conn_info->resp_ie_len = 0; + conn_info->resp_ie_len = + assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + memcpy(conn_info->resp_ie, cfg->extra_buf, + conn_info->resp_ie_len); } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); +exit: + if (err) { + WL_ERR(("err:%d assoc-req:%u,resp:%u conn-req:%u,resp:%u\n", + err, assoc_info.req_len, assoc_info.resp_len, + conn_info->req_ie_len, conn_info->resp_ie_len)); + } return err; } @@ -9474,6 +9519,7 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 channel; struct ieee80211_channel *cur_channel; u32 freq, band; + char *buf; wiphy = bcmcfg_to_wiphy(cfg); @@ -9481,15 +9527,20 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); mutex_lock(&cfg->usr_sync); + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC); + if (!buf) { + WL_ERR(("buffer alloc failed.\n")); + return BCME_NOMEM; + } - *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX); - err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, - cfg->extra_buf, WL_EXTRA_BUF_MAX, false); + *(u32 *) buf = htod32(WL_EXTRA_BUF_MAX); + err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, + buf, WL_EXTRA_BUF_MAX); if (unlikely(err)) { WL_ERR(("Could not get bss info %d\n", err)); goto update_bss_info_out; } - bi = (struct wl_bss_info *)(cfg->extra_buf + 4); + bi = (struct wl_bss_info *)(buf + 4); channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN); #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) @@ -9544,8 +9595,9 @@ static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, * information out of probe response. * so we speficially query dtim information. */ - err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), false); + dtim_period = 0; + err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period)); if (unlikely(err)) { WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); goto update_bss_info_out; @@ -9559,6 +9611,8 @@ update_bss_info_out: if (unlikely(err)) { WL_ERR(("Failed with error %d\n", err)); } + + kfree(buf); mutex_unlock(&cfg->usr_sync); return err; } @@ -9776,12 +9830,8 @@ wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); #endif /* GSCAN_SUPPORT */ - if (!data) { - WL_ERR(("Data is NULL!\n")); - return 0; - } + WL_ERR((">>> PNO Event\n")); - WL_DBG((">>> PNO Event\n")); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); #ifdef GSCAN_SUPPORT @@ -9871,13 +9921,10 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } break; case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = - dhd_dev_process_full_gscan_result(ndev, data, len, - &send_evt_bytes); + ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes); if (ptr) { wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, - send_evt_bytes); + GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); kfree(ptr); } else { err = -ENOMEM; @@ -9921,8 +9968,9 @@ wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, mutex_lock(&cfg->usr_sync); wl_clr_drv_status(cfg, SCANNING, ndev); - err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, - sizeof(channel_inform), false); + memset(&channel_inform, 0, sizeof(channel_inform)); + err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &channel_inform, + sizeof(channel_inform)); if (unlikely(err)) { WL_ERR(("scan busy (%d)\n", err)); goto scan_done_out; @@ -9937,7 +9985,7 @@ wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, bss_list = cfg->bss_list; memset(bss_list, 0, len); bss_list->buflen = htod32(len); - err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); + err = wldev_ioctl_get(ndev, WLC_SCAN_RESULTS, bss_list, len); if (unlikely(err) && unlikely(!cfg->scan_suppressed)) { WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); err = -EINVAL; @@ -10064,21 +10112,26 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wifi_p2p_pub_act_frame_t *act_frm = NULL; wifi_p2p_action_frame_t *p2p_act_frm = NULL; wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; - wl_event_rx_frame_data_t *rxframe = - (wl_event_rx_frame_data_t*)data; - u32 event = ntoh32(e->event_type); + wl_event_rx_frame_data_t *rxframe; + u32 event; u8 *mgmt_frame; - u8 bsscfgidx = e->bsscfgidx; - u32 mgmt_frame_len = ntoh32(e->datalen); - u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); + u8 bsscfgidx; + u32 mgmt_frame_len; + u16 channel; bool retval; - - if (mgmt_frame_len < sizeof(wl_event_rx_frame_data_t)) { - WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); + if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) { + WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen))); return -EINVAL; } - mgmt_frame_len -= sizeof(wl_event_rx_frame_data_t); - + mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + event = ntoh32(e->event_type); + bsscfgidx = e->bsscfgidx; + rxframe = (wl_event_rx_frame_data_t *)data; + if (!rxframe) { + WL_ERR(("rxframe: NULL\n")); + return -EINVAL; + } + channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK); memset(&bssid, 0, ETHER_ADDR_LEN); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); @@ -10101,7 +10154,7 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); if (err < 0) WL_ERR(("WLC_GET_BSSID error %d\n", err)); memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); @@ -10215,13 +10268,10 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_DBG((" Event WLC_E_PROBREQ_MSG received\n")); mgmt_frame = (u8 *)(data); mgmt_frame_len = ntoh32(e->datalen); - if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) { - WL_ERR(("WLC_E_PROBREQ_MSG - wrong datalen:%d\n", - mgmt_frame_len)); + WL_ERR(("wrong datalen:%d\n", mgmt_frame_len)); return -EINVAL; } - prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN; /* Parse prob_req IEs */ @@ -10709,7 +10759,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(100); + (void)schedule_timeout(HZ); set_current_state(TASK_RUNNING); refcnt++; } @@ -10756,7 +10806,7 @@ static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg) err = -ENOMEM; } else { /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); + err = wldev_ioctl_set(dev, WLC_SCAN, params, params_size); if (err < 0) { WL_ERR(("scan abort failed \n")); } @@ -10945,11 +10995,9 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Invalid escan result (NULL pointer)\n")); goto exit; } - if ((dtoh32(escan_result->buflen) > ESCAN_BUF_SIZE) || - (dtoh32(escan_result->buflen) < - sizeof(wl_escan_result_t))) { - WL_ERR(("Invalid escan buffer len:%d\n", - dtoh32(escan_result->buflen))); + if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) || + (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) { + WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen))); goto exit; } if (dtoh16(escan_result->bss_count) != 1) { @@ -11185,16 +11233,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT); } -#ifdef GSCAN_SUPPORT - else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN)) { - if (status == WLC_E_STATUS_NEWSCAN) { - WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request)); - WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, - escan_result->bss_count)); - } -#else else if (status == WLC_E_STATUS_ABORT) { -#endif /* GSCAN_SUPPORT */ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; wl_escan_print_sync_id(status, escan_result->sync_id, cfg->escan_info.cur_sync_id); @@ -11368,8 +11407,8 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ if (iter->pm_restore) continue; /* Save the current power mode */ - err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, - sizeof(iter->pm), false); + err = wldev_ioctl_get(iter->ndev, WLC_GET_PM, &iter->pm, + sizeof(iter->pm)); WL_DBG(("%s:power save %s\n", iter->ndev->name, iter->pm ? "enabled" : "disabled")); if (!err && iter->pm) { @@ -11380,8 +11419,8 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ for_each_ndev(cfg, iter, next) { if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev)) continue; - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { + if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm))) != 0) { if (err == -ENODEV) WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); else @@ -11405,8 +11444,8 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ if (iter->pm_restore) continue; /* Save the current power mode */ - err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, - sizeof(iter->pm), false); + err = wldev_ioctl_get(iter->ndev, WLC_GET_PM, &iter->pm, + sizeof(iter->pm)); WL_DBG(("%s:power save %s\n", iter->ndev->name, iter->pm ? "enabled" : "disabled")); if (!err && iter->pm) { @@ -11417,8 +11456,8 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ for_each_ndev(cfg, iter, next) { if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev)) continue; - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { + if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm))) != 0) { if (err == -ENODEV) WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); else @@ -11455,8 +11494,8 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ if (iter->pm_restore && iter->pm) { WL_DBG(("%s:restoring power save %s\n", iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); - err = wldev_ioctl(iter->ndev, - WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); + err = wldev_ioctl_set(iter->ndev, + WLC_SET_PM, &iter->pm, sizeof(iter->pm)); if (unlikely(err)) { if (err == -ENODEV) WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); @@ -12031,7 +12070,7 @@ static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s return err; } infra = htod32(infra); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); + err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); if (unlikely(err)) { WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); return err; @@ -12073,9 +12112,7 @@ s32 wl_cfg80211_apply_eventbuffer( mutex_lock(&cfg->event_sync); /* Read event_msgs mask */ - bcm_mkiovar("event_msgs", NULL, 0, iovbuf, - sizeof(iovbuf)); - ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); + ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); if (unlikely(ret)) { WL_ERR(("Get event_msgs error (%d)\n", ret)); goto exit; @@ -12091,9 +12128,8 @@ s32 wl_cfg80211_apply_eventbuffer( } /* Write updated Event mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf)); - ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf, + sizeof(iovbuf), NULL); if (unlikely(ret)) { WL_ERR(("Set event_msgs error (%d)\n", ret)); } @@ -12116,9 +12152,7 @@ s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) mutex_lock(&cfg->event_sync); /* Setup event_msgs */ - bcm_mkiovar("event_msgs", NULL, 0, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); + err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL); if (unlikely(err)) { WL_ERR(("Get event_msgs error (%d)\n", err)); goto eventmsg_out; @@ -12129,9 +12163,8 @@ s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) } else { clrbit(eventmask, event); } - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf), NULL); if (unlikely(err)) { WL_ERR(("Set event_msgs error (%d)\n", err)); goto eventmsg_out; @@ -12163,9 +12196,6 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) WL_ERR(("failed to allocate local buf\n")); return -ENOMEM; } - list = (wl_uint32_list_t *)(void *)pbuf; - list->count = htod32(WL_NUMCHANSPECS); - err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync); @@ -12177,6 +12207,13 @@ static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap) #undef LOCAL_BUF_LEN list = (wl_uint32_list_t *)(void *)pbuf; + + if ((list) && (dtoh32(list->count) > htod32(WL_NUMCHANSPECS))) { + WL_ERR(("Invalid channel list : %d\n", dtoh32(list->count))); + kfree(pbuf); + return INVCHANSPEC; + } + band = array_size = n_2g = n_5g = 0; for (i = 0; i < dtoh32(list->count); i++) { index = 0; @@ -12330,14 +12367,14 @@ s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) dev = bcmcfg_to_prmry_ndev(cfg); memset(bandlist, 0, sizeof(bandlist)); - err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, - sizeof(bandlist), false); + err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist, + sizeof(bandlist)); if (unlikely(err)) { WL_ERR(("error read bandlist (%d)\n", err)); goto end_bands; } - err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, - sizeof(s32), false); + err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, + sizeof(s32)); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); goto end_bands; @@ -12715,8 +12752,8 @@ s32 wl_cfg80211_up(void *para) WL_DBG(("In\n")); cfg = g_bcm_cfg; - if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, - sizeof(int), false) < 0)) { + if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val, + sizeof(int)) < 0)) { WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); return err; } @@ -12920,7 +12957,7 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i { u8 *ssidie; int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); - int32 remaining_ie_buf_len, available_buffer_len; + int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); /* ERROR out if * 1. No ssid IE is FOUND or @@ -12934,24 +12971,28 @@ static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *i } available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream); remaining_ie_buf_len = available_buffer_len - (int)ssidie[1]; - if ((ssid_len > ssidie[1]) || - (ssidie[1] > available_buffer_len)) { + unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size); + if (ssidie[1] > available_buffer_len) { + WL_ERR(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__)); return; } if (ssidie[1] != ssid_len) { if (ssidie[1]) { - WL_ERR(("%s: Wrong SSID len: %d != %d\n", + WL_INFORM(("%s: Wrong SSID len: %d != %d\n", __FUNCTION__, ssidie[1], bi->SSID_len)); } - if (roam) { - WL_ERR(("Changing the SSID Info.\n")); + if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { + WL_INFORM(("Changing the SSID Info.\n")); memmove(ssidie + ssid_len + 2, (ssidie + 2) + ssidie[1], remaining_ie_buf_len); memcpy(ssidie + 2, bi->SSID, ssid_len); *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; + } else if (ssid_len < ssidie[1]) { + WL_ERR(("%s: Invalid SSID len: %d < %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); } return; } @@ -13363,7 +13404,7 @@ wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev) /* Set interface up, explicitly. */ val = 1; - ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); + ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val)); if (ret < 0) { WL_ERR(("set interface up failed, error = %d\n", ret)); goto done; @@ -13423,14 +13464,9 @@ wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen) { s32 ret = BCME_ERROR; struct bcm_cfg80211 *cfg = NULL; - wl_uint32_list_t *list = NULL; chanspec_t chanspec = 0; - memset(buf, 0, buflen); - cfg = g_bcm_cfg; - list = (wl_uint32_list_t *)buf; - list->count = htod32(WL_NUMCHANSPECS); /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | @@ -13457,11 +13493,7 @@ wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) wl_uint32_list_t *list = NULL; chanspec_t chanspec = 0; - memset(buf, 0, buflen); - cfg = g_bcm_cfg; - list = (wl_uint32_list_t *)buf; - list->count = htod32(WL_NUMCHANSPECS); /* Restrict channels to 5GHz, 20MHz BW, no SB. */ chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | @@ -13475,6 +13507,7 @@ wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) goto done; } + list = (wl_uint32_list_t *)buf; /* Skip DFS and inavlid P2P channel. */ for (i = 0, j = 0; i < dtoh32(list->count); i++) { chanspec = (chanspec_t) dtoh32(list->element[i]); @@ -13511,7 +13544,7 @@ wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, int retry = 0; /* Start auto channel selection scan. */ - ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true); + ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen); if (ret < 0) { WL_ERR(("can't start auto channel scan, error = %d\n", ret)); *channel = 0; @@ -13523,9 +13556,8 @@ wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, while (retry--) { OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); - - ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), - false); + chosen = 0; + ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); if ((ret == 0) && (dtoh32(chosen) != 0)) { *channel = (u16)(chosen & 0x00FF); WL_INFORM(("selected channel = %d\n", *channel)); @@ -13942,10 +13974,12 @@ wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bss if (ie_id != DOT11_MNG_INTERWORKING_ID) return BCME_UNSUPPORTED; - if (data_len > IW_IES_MAX_BUF_LEN) { - WL_ERR(("wrong data_len:%d\n", data_len)); + /* access network options (1 octet) is the mandatory field */ + if (!data || data_len == 0 || data_len > IW_IES_MAX_BUF_LEN) { + WL_ERR(("wrong interworking IE (len=%d)\n", data_len)); return BCME_BADARG; } + /* Validate the pktflag parameter */ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | @@ -14111,8 +14145,8 @@ static void wl_cfg80211_work_handler(struct work_struct * work) (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS)) continue; if (iter->ndev) { - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, - &pm, sizeof(pm), true)) != 0) { + if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, + &pm, sizeof(pm))) != 0) { if (err == -ENODEV) WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); else diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h similarity index 99% rename from drivers/net/wireless/bcmdhd/wl_cfg80211.h rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h index 326700e4b5ff35ed72e49b7d728fb01b5091d38c..f1dfe77b95efcd9b19ee6af046b4ee4295e01722 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg80211.h @@ -373,12 +373,12 @@ struct net_info { }; /* association inform */ -#define MAX_REQ_LINE 1024 +#define MAX_REQ_LINE 1024u struct wl_connect_info { u8 req_ie[MAX_REQ_LINE]; - s32 req_ie_len; + u32 req_ie_len; u8 resp_ie[MAX_REQ_LINE]; - s32 resp_ie_len; + u32 resp_ie_len; }; /* firmware /nvram downloading controller */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c similarity index 96% rename from drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c index 468d3f3ba13eaa8f8e82dfc8d8f6d30cbc239560..1706c4a82033f117d931e1551af3d180255bad7d 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfg_btcoex.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg_btcoex.c 637933 2016-05-16 08:21:50Z $ + * $Id: wl_cfg_btcoex.c 701287 2017-05-24 10:33:19Z $ */ #include @@ -89,9 +89,13 @@ dev_wlc_intvar_get_reg(struct net_device *dev, char *name, } var; int error; - bcm_mkiovar(name, (char *)(®), sizeof(reg), + memset(&var, 0, sizeof(var)); + error = bcm_mkiovar(name, (char *)(®), sizeof(reg), (char *)(&var), sizeof(var.buf)); - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); + if (error == 0) { + return BCME_BUFTOOSHORT; + } + error = wldev_ioctl_get(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf)); *retval = dtoh32(var.val); return (error); @@ -101,10 +105,15 @@ static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) { char ioctlbuf_local[WLC_IOCTL_SMLEN]; + int ret; + + memset(ioctlbuf_local, 0, sizeof(ioctlbuf_local)); + ret = bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); - bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); + if (ret == 0) + return BCME_BUFTOOSHORT; - return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); + return (wldev_ioctl_set(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local))); } /* get named driver variable to uint register value and return error indication diff --git a/drivers/net/wireless/bcmdhd/wl_cfgnan.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.c similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_cfgnan.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.c diff --git a/drivers/net/wireless/bcmdhd/wl_cfgnan.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.h similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_cfgnan.h rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfgnan.h diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c similarity index 99% rename from drivers/net/wireless/bcmdhd/wl_cfgp2p.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c index af10ad5d4d18052259b99b74fcac2fc75338e08f..ff6e8a2045ad9fadfa52aee0c0271594f0d68c56 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.c 528497 2015-01-22 10:58:38Z $ + * $Id: wl_cfgp2p.c 711632 2017-07-19 04:24:04Z $ * */ #include @@ -372,13 +372,13 @@ wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg) } if (val == 0) { val = 1; - ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); + ret = wldev_ioctl_set(ndev, WLC_DOWN, &val, sizeof(s32)); if (ret < 0) { CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); return ret; } wldev_iovar_setint(ndev, "apsta", val); - ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); + ret = wldev_ioctl_set(ndev, WLC_UP, &val, sizeof(s32)); if (ret < 0) { CFGP2P_ERR(("WLC_UP error %d\n", ret)); return ret; @@ -428,7 +428,7 @@ wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, if (unlikely(err < 0)) printk("'cfg p2p_ifadd' error %d\n", err); else if (if_type == WL_P2P_IF_GO) { - err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); + err = wldev_ioctl_set(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32)); if (unlikely(err < 0)) printk("'cfg scb_timeout' error %d\n", err); } @@ -508,7 +508,7 @@ wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, if (unlikely(err < 0)) { printk("'cfg p2p_ifupd' error %d\n", err); } else if (if_type == WL_P2P_IF_GO) { - err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); + err = wldev_ioctl_set(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32)); if (unlikely(err < 0)) printk("'cfg scb_timeout' error %d\n", err); } @@ -2236,8 +2236,8 @@ wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* bu } if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { - ret = wldev_ioctl(dev, - WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); + ret = wldev_ioctl_set(dev, + WLC_SET_PM, &legacy_ps, sizeof(legacy_ps)); if (unlikely(ret)) CFGP2P_ERR(("error (%d)\n", ret)); wl_cfg80211_update_power_mode(dev); @@ -2321,8 +2321,9 @@ wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib) return pAttrib; } else { - parse += (ie->len + TLV_HDR_LEN); - len -= (ie->len + TLV_HDR_LEN); + /* move to next IE */ + len -= (u32)((u8 *)ie + TLV_HDR_LEN + ie->len - parse); + parse = (uint8 *)ie + TLV_HDR_LEN + ie->len; CFGP2P_INFO(("P2P Attribute %d not found Moving parse" " to %p len to %d", attrib, parse, len)); } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_cfgp2p.h rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfgp2p.h diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c similarity index 98% rename from drivers/net/wireless/bcmdhd/wl_cfgvendor.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c index 65bd87c8fb323e342167c4ad87540d71ecd29903..e88fd72894599e4437a6708d9e46a6d0e954204c 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.c @@ -736,33 +736,10 @@ wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy, nla_for_each_attr(iter, data, len, tmp2) { type = nla_type(iter); switch (type) { - case GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT: - if (nla_len(iter) != sizeof(uint32)) { - WL_DBG(("type:%d length:%d not matching.\n", - type, nla_len(inner))); - err = -EINVAL; - goto exit; - } - hotlist_params->nbssid = (uint16)nla_get_u32(iter); - if ((hotlist_params->nbssid == 0) || - (hotlist_params->nbssid > PFN_SWC_MAX_NUM_APS)) { - WL_ERR(("nbssid:%d exceed limit.\n", - hotlist_params->nbssid)); - err = -EINVAL; - goto exit; - } - break; case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS: - if (hotlist_params->nbssid == 0) { - WL_ERR(("nbssid not retrieved.\n")); - err = -EINVAL; - goto exit; - } pbssid = hotlist_params->bssid; nla_for_each_nested(outer, iter, tmp) { nla_for_each_nested(inner, outer, tmp1) { - if (j >= hotlist_params->nbssid) - break; type = nla_type(inner); switch (type) { @@ -802,14 +779,12 @@ wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy, goto exit; } } - j++; - } - if (j != hotlist_params->nbssid) { - WL_ERR(("bssid_cnt:%d != nbssid:%d.\n", j, - hotlist_params->nbssid)); - err = -EINVAL; - goto exit; + if (++j >= PFN_SWC_MAX_NUM_APS) { + WL_ERR(("cap hotlist max:%d\n", j)); + break; + } } + hotlist_params->nbssid = j; break; case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: if (nla_len(iter) != sizeof(uint8)) { diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h similarity index 99% rename from drivers/net/wireless/bcmdhd/wl_cfgvendor.h rename to drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h index ae80b74a032621e65a8482187598351a716f3b76..e6f7ce882ff07714d0c7617f7c8fc9605c1f7a1b 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/wl_cfgvendor.h @@ -167,7 +167,6 @@ enum gscan_attributes { GSCAN_ATTRIBUTE_RSSI_HIGH, GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM, GSCAN_ATTRIBUTE_HOTLIST_FLUSH, - GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, /* remaining reserved for additional attributes */ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, diff --git a/drivers/net/wireless/bcmdhd/wl_dbg.h b/drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_dbg.h rename to drivers/net/wireless/bcmdhd_bcm4356/wl_dbg.h diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_linux_mon.c similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_linux_mon.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_linux_mon.c diff --git a/drivers/net/wireless/bcmdhd/wl_roam.c b/drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c similarity index 100% rename from drivers/net/wireless/bcmdhd/wl_roam.c rename to drivers/net/wireless/bcmdhd_bcm4356/wl_roam.c diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c similarity index 81% rename from drivers/net/wireless/bcmdhd/wldev_common.c rename to drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c index 5684326bd1db3bbcb1840d222e8b3c18974a05a7..b4aa5063a2797847057a04d3f0fd4e145e0d68c6 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wldev_common.c 538678 2015-03-04 13:28:49Z $ + * $Id: wldev_common.c 701287 2017-05-24 10:33:19Z $ */ #include @@ -31,6 +31,7 @@ #include #include +#include #define htod32(i) (i) #define htod16(i) (i) @@ -47,7 +48,7 @@ extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); -s32 wldev_ioctl( +static s32 wldev_ioctl( struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) { s32 ret = 0; @@ -65,6 +66,33 @@ s32 wldev_ioctl( return ret; } +/* +SET commands : +cast buffer to non-const and call the GET function +*/ + +s32 wldev_ioctl_set( + struct net_device *dev, u32 cmd, const void *arg, u32 len) +{ + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + return wldev_ioctl(dev, cmd, (void *)arg, len, 1); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +} + + +s32 wldev_ioctl_get( + struct net_device *dev, u32 cmd, void *arg, u32 len) +{ + return wldev_ioctl(dev, cmd, (void *)arg, len, 0); +} + /* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be * taken care of in dhd_ioctl_entry. Internal use only, not exposed to * wl_iw, wl_cfg80211 and wl_cfgp2p @@ -87,8 +115,24 @@ s32 wldev_iovar_getbuf( if (buf_sync) { mutex_lock(buf_sync); } - wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); - ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); + + if (buf && (buflen > 0)) { + /* initialize the response buffer */ + memset(buf, 0, buflen); + } else { + ret = BCME_BADARG; + goto exit; + } + + ret = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + + if (!ret) { + ret = BCME_BUFTOOSHORT; + goto exit; + } + ret = wldev_ioctl_get(dev, WLC_GET_VAR, buf, buflen); + +exit: if (buf_sync) mutex_unlock(buf_sync); return ret; @@ -104,12 +148,20 @@ s32 wldev_iovar_setbuf( if (buf_sync) { mutex_lock(buf_sync); } + if (buf && (buflen > 0)) { + /* initialize the response buffer */ + memset(buf, 0, buflen); + } else { + ret = BCME_BADARG; + goto exit; + } iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); if (iovar_len > 0) - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + ret = wldev_ioctl_set(dev, WLC_SET_VAR, buf, iovar_len); else ret = BCME_BUFTOOSHORT; +exit: if (buf_sync) mutex_unlock(buf_sync); return ret; @@ -158,6 +210,11 @@ s32 wldev_mkiovar_bsscfg( u32 namelen; u32 iolen; + /* initialize buffer */ + if (!iovar_buf || buflen == 0) + return BCME_BADARG; + memset(iovar_buf, 0, buflen); + if (bssidx == 0) { return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, (s8 *) iovar_buf, buflen); @@ -206,7 +263,7 @@ s32 wldev_iovar_getbuf_bsscfg( } wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); + ret = wldev_ioctl_get(dev, WLC_GET_VAR, buf, buflen); if (buf_sync) { mutex_unlock(buf_sync); } @@ -225,7 +282,7 @@ s32 wldev_iovar_setbuf_bsscfg( } iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); if (iovar_len > 0) - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + ret = wldev_ioctl_set(dev, WLC_SET_VAR, buf, iovar_len); else { ret = BCME_BUFTOOSHORT; } @@ -242,7 +299,7 @@ s32 wldev_iovar_setint_bsscfg( s8 iovar_buf[WLC_IOCTL_SMLEN]; val = htod32(val); - memset(iovar_buf, 0, sizeof(iovar_buf)); + return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, sizeof(iovar_buf), bssidx, NULL); } @@ -272,7 +329,8 @@ int wldev_get_link_speed( if (!plink_speed) return -ENOMEM; - error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); + *plink_speed = 0; + error = wldev_ioctl_get(dev, WLC_GET_RATE, plink_speed, sizeof(int)); if (unlikely(error)) return error; @@ -289,7 +347,8 @@ int wldev_get_rssi( if (!scb_val) return -ENOMEM; - error = wldev_ioctl(dev, WLC_GET_RSSI, scb_val, sizeof(scb_val_t), 0); + memset(scb_val, 0, sizeof(scb_val_t)); + error = wldev_ioctl_get(dev, WLC_GET_RSSI, scb_val, sizeof(scb_val_t)); if (unlikely(error)) return error; @@ -303,7 +362,8 @@ int wldev_get_ssid( if (!pssid) return -ENOMEM; - error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); + memset(pssid, 0, sizeof(wlc_ssid_t)); + error = wldev_ioctl_get(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t)); if (unlikely(error)) return error; pssid->SSID_len = dtoh32(pssid->SSID_len); @@ -315,7 +375,8 @@ int wldev_get_band( { int error; - error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); + *pband = 0; + error = wldev_ioctl_get(dev, WLC_GET_BAND, pband, sizeof(uint)); return error; } @@ -325,7 +386,7 @@ int wldev_set_band( int error = -1; if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { - error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); + error = wldev_ioctl_set(dev, WLC_SET_BAND, &band, sizeof(band)); if (!error) dhd_bus_band_set(dev, band); } @@ -336,7 +397,7 @@ int wldev_get_datarate(struct net_device *dev, int *datarate) { int error = 0; - error = wldev_ioctl(dev, WLC_GET_RATE, datarate, sizeof(int), false); + error = wldev_ioctl_get(dev, WLC_GET_RATE, datarate, sizeof(int)); if (error) { return -1; } else { @@ -359,14 +420,14 @@ int wldev_get_mode( wl_bss_info_t *bss = NULL; char* buf = NULL; - buf = kmalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!buf) { WLDEV_ERROR(("%s:NOMEM\n", __FUNCTION__)); return -ENOMEM; } *(u32*) buf = htod32(WL_EXTRA_BUF_MAX); - error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void*)buf, WL_EXTRA_BUF_MAX, false); + error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void*)buf, WL_EXTRA_BUF_MAX); if (error) { WLDEV_ERROR(("%s:failed:%d\n", __FUNCTION__, error)); kfree(buf); @@ -413,6 +474,9 @@ int wldev_set_country( wl_country_t cspec = {{0}, 0, {0}}; scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; + struct wireless_dev *wdev = ndev_to_wdev(dev); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); if (!country_code) return error; @@ -427,9 +491,9 @@ int wldev_set_country( if ((error < 0) || (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { - if (user_enforced) { + if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { bzero(&scbval, sizeof(scb_val_t)); - error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); + error = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); if (error < 0) { WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", __FUNCTION__, error)); diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h similarity index 94% rename from drivers/net/wireless/bcmdhd/wldev_common.h rename to drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h index 642d45ea553a95faf9dd3dab5147bd5e8d0cdeda..bf15bd40efc5c761ae39173ac0fc4a51e6c06324 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd_bcm4356/wldev_common.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wldev_common.h 528551 2015-01-22 14:00:54Z $ + * $Id: wldev_common.h 701287 2017-05-24 10:33:19Z $ */ #ifndef __WLDEV_COMMON_H__ #define __WLDEV_COMMON_H__ @@ -32,8 +32,11 @@ * netdev_ops->ndo_do_ioctl in new kernels) * @dev: the net_device handle */ -s32 wldev_ioctl( - struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); +s32 wldev_ioctl_get( + struct net_device *dev, u32 cmd, void *arg, u32 len); + +s32 wldev_ioctl_set( + struct net_device *dev, u32 cmd, const void *arg, u32 len); /** Retrieve named IOVARs, this function calls wl_dev_ioctl with * WLC_GET_VAR IOCTL code @@ -101,7 +104,7 @@ extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); extern int net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_set_suspend_disable(struct net_device *dev, int val); extern int net_os_set_suspend(struct net_device *dev, int val, int force); -extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, +extern int wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left); /* Get the link speed from dongle, speed is in kpbs */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 8afb609253325ff2fdf004e96f4503353d649918..fef9ab790d1963bf7f3fd64c7f882c29d74e18dc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -3918,24 +3918,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, static int brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac) + struct station_del_parameters *params) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_scb_val_le scbval; struct brcmf_if *ifp = netdev_priv(ndev); s32 err; - if (!mac) + if (!params->mac) return -EFAULT; - brcmf_dbg(TRACE, "Enter %pM\n", mac); + brcmf_dbg(TRACE, "Enter %pM\n", params->mac); if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; if (!check_vif_up(ifp->vif)) return -EIO; - memcpy(&scbval.ea, mac, ETH_ALEN); + memcpy(&scbval.ea, params->mac, ETH_ALEN); scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scbval)); diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 99dab03299b9f2a6a4c6f72743248285188e08b6..f5032045df4962fc0f1f2253132f931e1bae6502 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -3,6 +3,7 @@ config CNSS select CRYPTO select CRYPTO_HASH select CRYPTO_BLKCIPHER + select CNSS_CRYPTO ---help--- This module adds support for the CNSS connectivity subsystem used for wifi devices based on the QCA AR6320 chipset. @@ -24,6 +25,7 @@ config CNSS_PCI config CNSS_SDIO tristate "Flag to enable platform driver for SIDO based wifi device" + select CNSS depends on MMC_SDHCI depends on MMC_SDHCI_MSM ---help--- diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile index ff670f14dde3a3a5d395b8217830e66fe4e6e2df..4401158fe888d29e88d99e2fd10c255ee0c08937 100644 --- a/drivers/net/wireless/cnss/Makefile +++ b/drivers/net/wireless/cnss/Makefile @@ -1,6 +1,5 @@ # Makefile for CNSS platform driver -cnsscore-objs += ../wcnss/qcomwlan_secif.o obj-$(CONFIG_CNSS_PCI) += cnss_pci.o -obj-y += cnss_common.o -obj-y += cnsscore.o +obj-$(CONFIG_CNSS_SDIO) += cnss_sdio.o +obj-$(CONFIG_CNSS) += cnss_common.o diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index a9bde7b4f02deb97af78545597f4b09f399f5d85..98e5a989a6aa538da52a5751326d333665ee9a59 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1364,6 +1364,9 @@ static int cnss_wlan_pci_suspend(struct device *dev) if (!penv) goto out; + if (!penv->pcie_link_state) + goto out; + wdriver = penv->driver; if (!wdriver) goto out; @@ -1391,6 +1394,9 @@ static int cnss_wlan_pci_resume(struct device *dev) if (!penv) goto out; + if (!penv->pcie_link_state) + goto out; + wdriver = penv->driver; if (!wdriver) goto out; @@ -1592,6 +1598,13 @@ void cnss_schedule_recovery_work(void) } EXPORT_SYMBOL(cnss_schedule_recovery_work); +static inline void __cnss_disable_irq(void *data) +{ + struct pci_dev *pdev = data; + + disable_irq(pdev->irq); +} + void cnss_pci_events_cb(struct msm_pcie_notify *notify) { unsigned long flags; @@ -1612,6 +1625,7 @@ void cnss_pci_events_cb(struct msm_pcie_notify *notify) spin_unlock_irqrestore(&pci_link_down_lock, flags); pr_err("PCI link down, schedule recovery\n"); + __cnss_disable_irq(notify->user); schedule_work(&recovery_work); break; diff --git a/drivers/net/wireless/cnss_crypto/Makefile b/drivers/net/wireless/cnss_crypto/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cfe0285eb31ec624c006ec25b928a1a236e15f45 --- /dev/null +++ b/drivers/net/wireless/cnss_crypto/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CNSS_CRYPTO) += cnss_secif.o diff --git a/drivers/net/wireless/wcnss/qcomwlan_secif.c b/drivers/net/wireless/cnss_crypto/cnss_secif.c similarity index 93% rename from drivers/net/wireless/wcnss/qcomwlan_secif.c rename to drivers/net/wireless/cnss_crypto/cnss_secif.c index 381943a6d911af10cb0b55f385968801f76c6000..24202d3a7c58e60c3be5fb774c185ae8eec5ac43 100644 --- a/drivers/net/wireless/wcnss/qcomwlan_secif.c +++ b/drivers/net/wireless/cnss_crypto/cnss_secif.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, 2015, The Linux Foundation. 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 and @@ -91,7 +91,6 @@ static inline void leftshift_onebit(const u8 *input, u8 *output) output[i] |= overflow; overflow = (input[i] & 0x80) ? 1 : 0; } - return; } static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2) @@ -136,7 +135,6 @@ static inline void padding(u8 *lastb, u8 *pad, u16 length) } } - void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, u16 length, u8 *mac) { @@ -144,21 +142,21 @@ void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE]; u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128]; int cmpBlk; - int i, nBlocks = (length + 15)/AES_BLOCK_SIZE; + int i, nblocks = (length + 15) / AES_BLOCK_SIZE; generate_subkey(tfm, k1, k2); - if (nBlocks == 0) { - nBlocks = 1; + if (nblocks == 0) { + nblocks = 1; cmpBlk = 0; } else { cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0; } if (cmpBlk) { /* Last block is complete block */ - xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last); + xor_128(&m[AES_BLOCK_SIZE * (nblocks - 1)], k1, m_last); } else { /* Last block is not complete block */ - padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded, + padding(&m[AES_BLOCK_SIZE * (nblocks - 1)], padded, length % AES_BLOCK_SIZE); xor_128(padded, k2, m_last); } @@ -166,7 +164,7 @@ void wcnss_wlan_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, for (i = 0; i < AES_BLOCK_SIZE; i++) x[i] = 0; - for (i = 0; i < (nBlocks - 1); i++) { + for (i = 0; i < (nblocks - 1); i++) { xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */ crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */ } diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index 8cf48edbe5925c89998f27e73913a6a1b40739c0..b731926c01895a1d7a3e72aa3b54b38e6ca21154 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012,2014-2016 The Linux Foundation. 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 and @@ -42,50 +42,50 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 8 * 1024, NULL}, {0, 8 * 1024, NULL}, {0, 8 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 12 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 16 * 1024, NULL}, - {0, 24 * 1024, NULL}, - {0, 24 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 16 * 1024, NULL}, + {0, 32 * 1024, NULL}, + {0, 32 * 1024, NULL}, {0, 32 * 1024, NULL}, {0, 32 * 1024, NULL}, {0, 32 * 1024, NULL}, @@ -98,7 +98,8 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, - {0, 76 * 1024, NULL}, + {0, 128 * 1024, NULL}, + {0, 128 * 1024, NULL}, }; int wcnss_prealloc_init(void) @@ -157,7 +158,7 @@ void *wcnss_prealloc_get(unsigned int size) if (wcnss_allocs[i].occupied) continue; - if (wcnss_allocs[i].size > size) { + if (wcnss_allocs[i].size >= size) { /* we found the slot */ wcnss_allocs[i].occupied = 1; spin_unlock_irqrestore(&alloc_lock, flags); @@ -169,6 +170,7 @@ void *wcnss_prealloc_get(unsigned int size) pr_err("wcnss: %s: prealloc not available for size: %d\n", __func__, size); + WARN_ON(1); return NULL; } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 68f0bbe1f381f4b09303450b9520e3d107963a2d..9f2d8c8e22bd9eb507c450cf9f3e3d9958eccc0a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -365,7 +365,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) sta_id); continue; } - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); clear_bit(sta_id, mvm->sta_drained); } @@ -420,7 +420,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, } else { spin_unlock_bh(&mvm_sta->lock); ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); } return ret; @@ -434,7 +434,7 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); return ret; } @@ -456,7 +456,7 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); sta->sta_id = IWL_MVM_STATION_COUNT; } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 735c266203870518163ed10d30d93c4eb4d8562f..886904bab9a26d812a826fea91d3cafb6cade876 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -441,11 +441,16 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, struct mac80211_hwsim_data *data = hw->priv; u64 now = mac80211_hwsim_get_tsf(hw, vif); u32 bcn_int = data->beacon_int; - s64 delta = tsf - now; + u64 delta = abs64(tsf - now); - data->tsf_offset += delta; /* adjust after beaconing with new timestamp at old TBTT */ - data->bcn_delta = do_div(delta, bcn_int); + if (tsf > now) { + data->tsf_offset += delta; + data->bcn_delta = do_div(delta, bcn_int); + } else { + data->tsf_offset -= delta; + data->bcn_delta = -do_div(delta, bcn_int); + } } static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 923e348dda70c389e1a9982e72c260ad7f75fd20..5d4f85a1a4ed849fbd865f9f3aa0d89d06322923 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -550,6 +550,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 8169a85c44986034a958ee01b6dce7052402691c..9f33ff03e604c82c8b3d6e629efb0e88ab673b9b 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -358,9 +358,9 @@ struct ndis_80211_pmkid { #define CAP_MODE_80211G 4 #define CAP_MODE_MASK 7 -#define WORK_LINK_UP (1<<0) -#define WORK_LINK_DOWN (1<<1) -#define WORK_SET_MULTICAST_LIST (1<<2) +#define WORK_LINK_UP 0 +#define WORK_LINK_DOWN 1 +#define WORK_SET_MULTICAST_LIST 2 #define RNDIS_WLAN_ALG_NONE 0 #define RNDIS_WLAN_ALG_WEP (1<<0) @@ -1238,7 +1238,7 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); - if (rts_threshold < 0 || rts_threshold > 2347) + if (rts_threshold == -1 || rts_threshold > 2347) rts_threshold = 2347; tmp = cpu_to_le32(rts_threshold); @@ -1292,7 +1292,8 @@ static int set_channel(struct usbnet *usbdev, int channel) if (is_associated(usbdev)) return 0; - dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; + dsconfig = 1000 * + ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); len = sizeof(config); ret = rndis_query_oid(usbdev, @@ -3422,6 +3423,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); + if (!priv->workqueue) { + wiphy_free(wiphy); + return -ENOMEM; + } INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index db6430c1a08414650a894d3e8a6d41c57cba1711..a0e6d54aa2b288016bba33f48d8aa68b6f2d73c3 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index 6822b845efc15d5e2305bf468cf76c6bd83e1dce..86c0c39abeb2044da95f3c83035f2e6c0bc0f35f 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 4c67c2f9ea716a1c8d9430bcd51284867a20a4c8..c6e92848cd0e6d9647255829ff18a8d78384fdfc 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -119,8 +119,7 @@ static void wl1251_spi_wake(struct wl1251 *wl) crc[3] = cmd[6]; crc[4] = cmd[5]; - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; + cmd[4] = crc7_be(0, crc, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; t.tx_buf = cmd; t.len = WSPI_INIT_CMD_LEN; diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 29ef2492951fcdaa372611449fbc4c3cde4322f1..c2bf68c359a9e9fe3278a22813a93c1fffc2cf3c 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -348,6 +348,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index bfb57e671034cae26a087e1596ce8f3fb986be78..8747da8fcdcb1e4ab9a0d1fb5a58896941d07889 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -154,8 +154,7 @@ static void wl12xx_spi_init(struct device *child) crc[3] = cmd[6]; crc[4] = cmd[5]; - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; + cmd[4] = crc7_be(0, crc, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; t.tx_buf = cmd; t.len = WSPI_INIT_CMD_LEN; diff --git a/drivers/net/wireless/wcnss/Makefile b/drivers/net/wireless/wcnss/Makefile index 11fa673e056f05271dae3fb70b07332b62936226..072fef85044def3ba8c5cdaa51b3eb0b73d2fbc6 100644 --- a/drivers/net/wireless/wcnss/Makefile +++ b/drivers/net/wireless/wcnss/Makefile @@ -1,6 +1,6 @@ # Makefile for WCNSS triple-play driver -wcnsscore-objs += wcnss_wlan.o qcomwlan_secif.o wcnss_vreg.o +wcnsscore-objs += wcnss_wlan.o wcnss_vreg.o obj-$(CONFIG_WCNSS_CORE) += wcnsscore.o diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index d46c54143b89de4cec481483ddc62f9ee87f8bc4..8ddad28b2c839be79e42ec8ae3fed310c41c6560 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -24,6 +24,7 @@ #include #include #include +#include static void __iomem *msm_wcnss_base; @@ -32,6 +33,7 @@ static DEFINE_MUTEX(list_lock); static DEFINE_SEMAPHORE(wcnss_power_on_lock); static int auto_detect; static int is_power_on; +DEFINE_LED_TRIGGER(wlan_indication_led); #define RIVA_PMU_OFFSET 0x28 @@ -48,6 +50,7 @@ static int is_power_on; #define WCN3620 0x5111 #define WCN3620A 0x5112 #define WCN3610 0x9101 +#define WCN3610V1 0x9110 #define WCNSS_PMU_CFG_IRIS_XO_CFG BIT(3) #define WCNSS_PMU_CFG_IRIS_XO_EN BIT(4) @@ -66,15 +69,16 @@ static int is_power_on; #define VREG_SET_VOLTAGE_MASK 0x0002 #define VREG_OPTIMUM_MODE_MASK 0x0004 #define VREG_ENABLE_MASK 0x0008 +#define VDD_PA "qcom,iris-vddpa" #define WCNSS_INVALID_IRIS_REG 0xbaadbaad struct vregs_info { const char * const name; int state; - const int nominal_min; - const int low_power_min; - const int max_voltage; + int nominal_min; + int low_power_min; + int max_voltage; const int uA_load; struct regulator *regulator; }; @@ -153,6 +157,18 @@ static struct vregs_info pronto_vregs_pronto_v3[] = { 1800000, 0, NULL}, }; +/* WCNSS regulators for Pronto v4 hardware */ +static struct vregs_info pronto_vregs_pronto_v4[] = { + {"qcom,pronto-vddmx", VREG_NULL_CONFIG, RPM_REGULATOR_LEVEL_TURBO, + RPM_REGULATOR_LEVEL_NONE, RPM_REGULATOR_LEVEL_TURBO, + 0, NULL}, + {"qcom,pronto-vddcx", VREG_NULL_CONFIG, RPM_REGULATOR_LEVEL_NOM, + RPM_REGULATOR_LEVEL_NONE, RPM_REGULATOR_LEVEL_TURBO, + 0, NULL}, + {"qcom,pronto-vddpx", VREG_NULL_CONFIG, 1800000, 0, + 1800000, 0, NULL}, +}; + struct host_driver { char name[20]; @@ -185,6 +201,50 @@ int xo_auto_detect(u32 reg) } } +int wcnss_get_iris_name(char *iris_name) +{ + struct wcnss_wlan_config *cfg = NULL; + int iris_id; + + cfg = wcnss_get_wlan_config(); + + if (cfg) { + iris_id = cfg->iris_id; + iris_id = iris_id >> 16; + } else { + return 1; + } + + switch (iris_id) { + case WCN3660: + memcpy(iris_name, "WCN3660", sizeof("WCN3660")); + break; + case WCN3660A: + memcpy(iris_name, "WCN3660A", sizeof("WCN3660A")); + break; + case WCN3660B: + memcpy(iris_name, "WCN3660B", sizeof("WCN3660B")); + break; + case WCN3620: + memcpy(iris_name, "WCN3620", sizeof("WCN3620")); + break; + case WCN3620A: + memcpy(iris_name, "WCN3620A", sizeof("WCN3620A")); + break; + case WCN3610: + memcpy(iris_name, "WCN3610", sizeof("WCN3610")); + break; + case WCN3610V1: + memcpy(iris_name, "WCN3610V1", sizeof("WCN3610V1")); + break; + default: + return 1; + } + + return 0; +} +EXPORT_SYMBOL(wcnss_get_iris_name); + int validate_iris_chip_id(u32 reg) { int iris_id; @@ -197,6 +257,7 @@ int validate_iris_chip_id(u32 reg) case WCN3620: case WCN3620A: case WCN3610: + case WCN3610V1: return 0; default: return 1; @@ -344,6 +405,8 @@ configure_iris_xo(struct device *dev, else auto_detect = WCNSS_XO_INVALID; + cfg->iris_id = iris_reg; + /* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */ reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE); @@ -419,6 +482,14 @@ fail: static void wcnss_vregs_off(struct vregs_info regulators[], uint size) { int i, rc = 0; + struct wcnss_wlan_config *cfg; + + cfg = wcnss_get_wlan_config(); + + if (!cfg) { + pr_err("Faild to get WLAN configuration\n"); + return; + } /* Regulators need to be turned off in the reverse order */ for (i = (size-1); i >= 0; i--) { @@ -436,6 +507,13 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size) /* Set voltage to lowest level */ if (regulators[i].state & VREG_SET_VOLTAGE_MASK) { + + if (cfg->vbatt < WCNSS_VBATT_THRESHOLD + && !memcmp(regulators[i].name, + VDD_PA, sizeof(VDD_PA))) { + regulators[i].max_voltage = WCNSS_VBATT_LOW; + } + rc = regulator_set_voltage(regulators[i].regulator, regulators[i].low_power_min, regulators[i].max_voltage); @@ -465,6 +543,14 @@ static int wcnss_vregs_on(struct device *dev, struct vregs_info regulators[], uint size) { int i, rc = 0, reg_cnt; + struct wcnss_wlan_config *cfg; + + cfg = wcnss_get_wlan_config(); + + if (!cfg) { + pr_err("Faild to get WLAN configuration\n"); + return -EINVAL; + } for (i = 0; i < size; i++) { /* Get regulator source */ @@ -481,6 +567,14 @@ static int wcnss_vregs_on(struct device *dev, /* Set voltage to nominal. Exclude swtiches e.g. LVS */ if ((regulators[i].nominal_min || regulators[i].max_voltage) && (reg_cnt > 0)) { + + if (cfg->vbatt < WCNSS_VBATT_THRESHOLD + && !memcmp(regulators[i].name, + VDD_PA, sizeof(VDD_PA))) { + regulators[i].nominal_min = WCNSS_VBATT_INITIAL; + regulators[i].max_voltage = WCNSS_VBATT_LOW; + } + rc = regulator_set_voltage(regulators[i].regulator, regulators[i].nominal_min, regulators[i].max_voltage); @@ -530,7 +624,8 @@ static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type, wcnss_vregs_off(iris_vregs_riva, ARRAY_SIZE(iris_vregs_riva)); break; case WCNSS_PRONTO_HW: - if (cfg->is_pronto_vt || cfg->is_pronto_v3) { + if (cfg->is_pronto_vt || cfg->is_pronto_v3 + || cfg->is_pronto_v4) { wcnss_vregs_off(iris_vregs_pronto_v2, ARRAY_SIZE(iris_vregs_pronto_v2)); } else { @@ -556,7 +651,8 @@ static int wcnss_iris_vregs_on(struct device *dev, ARRAY_SIZE(iris_vregs_riva)); break; case WCNSS_PRONTO_HW: - if (cfg->is_pronto_vt || cfg->is_pronto_v3) { + if (cfg->is_pronto_vt || cfg->is_pronto_v3 + || cfg->is_pronto_v4) { ret = wcnss_vregs_on(dev, iris_vregs_pronto_v2, ARRAY_SIZE(iris_vregs_pronto_v2)); } else { @@ -584,6 +680,9 @@ static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type, } else if (cfg->is_pronto_v3) { wcnss_vregs_off(pronto_vregs_pronto_v3, ARRAY_SIZE(pronto_vregs_pronto_v3)); + } else if (cfg->is_pronto_v4) { + wcnss_vregs_off(pronto_vregs_pronto_v4, + ARRAY_SIZE(pronto_vregs_pronto_v4)); } else { wcnss_vregs_off(pronto_vregs, ARRAY_SIZE(pronto_vregs)); @@ -612,6 +711,9 @@ static int wcnss_core_vregs_on(struct device *dev, } else if (cfg->is_pronto_v3) { ret = wcnss_vregs_on(dev, pronto_vregs_pronto_v3, ARRAY_SIZE(pronto_vregs_pronto_v3)); + } else if (cfg->is_pronto_v4) { + ret = wcnss_vregs_on(dev, pronto_vregs_pronto_v4, + ARRAY_SIZE(pronto_vregs_pronto_v4)); } else { ret = wcnss_vregs_on(dev, pronto_vregs, ARRAY_SIZE(pronto_vregs)); @@ -702,6 +804,9 @@ int wcnss_req_power_on_lock(char *driver_name) list_add(&node->list, &power_on_lock_list); mutex_unlock(&list_lock); + if (wlan_indication_led) + led_trigger_event(wlan_indication_led, LED_FULL); + return 0; err: @@ -728,6 +833,15 @@ int wcnss_free_power_on_lock(char *driver_name) up(&wcnss_power_on_lock); mutex_unlock(&list_lock); + if (wlan_indication_led) + led_trigger_event(wlan_indication_led, LED_OFF); + return ret; } EXPORT_SYMBOL(wcnss_free_power_on_lock); + +void wcnss_en_wlan_led_trigger(void) +{ + led_trigger_register_simple("wlan-indication-led", + &wlan_indication_led); +} diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 153d4738ff00d06f35ca268358ff2f5dcee01305..a05b2796e61c67898956e6e424ee3d65a307cfb6 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -56,6 +56,7 @@ #define WCNSS_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE #define WCNSS_PM_QOS_TIMEOUT 15000 #define IS_CAL_DATA_PRESENT 0 +#define WAIT_FOR_CBC_IND 2 /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) @@ -179,10 +180,6 @@ static DEFINE_SPINLOCK(reg_spinlock); #define MCU_FDBR_FDAHB_TIMEOUT_OFFSET 0x3ac #define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024 -#define WCNSS_VBATT_THRESHOLD 3500000 -#define WCNSS_VBATT_GUARD 20000 -#define WCNSS_VBATT_HIGH 3700000 -#define WCNSS_VBATT_LOW 3300000 #define WCNSS_CTRL_CHANNEL "WCNSS_CTRL" #define WCNSS_MAX_FRAME_SIZE (4*1024) @@ -191,6 +188,7 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_MAX_CMD_LEN (128) #define WCNSS_MIN_CMD_LEN (3) #define WCNSS_MIN_SERIAL_LEN (6) +#define WCNSS_CMD_INFO_LEN 2 /* control messages from userspace */ #define WCNSS_USR_CTRL_MSG_START 0x00000000 @@ -199,6 +197,8 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_USR_WLAN_MAC_ADDR (WCNSS_USR_CTRL_MSG_START + 3) #define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define SHOW_MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x\n" +#define WCNSS_USER_MAC_ADDR_LENGTH 18 /* message types */ #define WCNSS_CTRL_MSG_START 0x01000000 @@ -214,6 +214,7 @@ static DEFINE_SPINLOCK(reg_spinlock); #define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9) #define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10) #define WCNSS_PM_CONFIG_REQ (WCNSS_CTRL_MSG_START + 11) +#define WCNSS_CBC_COMPLETE_IND (WCNSS_CTRL_MSG_START + 12) /* max 20mhz channel count */ #define WCNSS_MAX_CH_NUM 45 @@ -369,6 +370,7 @@ static struct { int triggered; int smd_channel_ready; u32 wlan_rx_buff_count; + int is_vsys_adc_channel; smd_channel_t *smd_ch; unsigned char wcnss_version[WCNSS_VERSION_LEN]; unsigned char fw_major; @@ -384,6 +386,7 @@ static struct { struct work_struct wcnss_pm_config_work; struct work_struct wcnssctrl_nvbin_dnld_work; struct work_struct wcnssctrl_rx_work; + struct work_struct wcnss_vadc_work; struct wake_lock wcnss_wake_lock; void __iomem *msm_wcnss_base; void __iomem *riva_ccu_base; @@ -399,6 +402,7 @@ static struct { void __iomem *alarms_tactl; void __iomem *fiq_reg; int nv_downloaded; + int is_cbc_done; unsigned char *fw_cal_data; unsigned char *user_cal_data; int fw_cal_rcvd; @@ -417,6 +421,7 @@ static struct { wait_queue_head_t read_wait; struct qpnp_adc_tm_btm_param vbat_monitor_params; struct qpnp_adc_tm_chip *adc_tm_dev; + struct qpnp_vadc_chip *vadc_dev; struct mutex vbat_monitor_mutex; u16 unsafe_ch_count; u16 unsafe_ch_list[WCNSS_MAX_CH_NUM]; @@ -437,29 +442,30 @@ static struct { static ssize_t wcnss_wlan_macaddr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - char macAddr[WLAN_MAC_ADDR_SIZE]; + int index; + int macAddr[WLAN_MAC_ADDR_SIZE]; if (!penv) return -ENODEV; - pr_debug("%s: Receive MAC Addr From user space: %s\n", __func__, buf); + if (WCNSS_USER_MAC_ADDR_LENGTH != strlen(buf)) { + dev_err(dev, "%s: Invalid MAC addr length\n", __func__); + return -EINVAL; + } if (WLAN_MAC_ADDR_SIZE != sscanf(buf, MAC_ADDRESS_STR, - (int *)&macAddr[0], (int *)&macAddr[1], - (int *)&macAddr[2], (int *)&macAddr[3], - (int *)&macAddr[4], (int *)&macAddr[5])) { - + &macAddr[0], &macAddr[1], &macAddr[2], + &macAddr[3], &macAddr[4], &macAddr[5])) { pr_err("%s: Failed to Copy MAC\n", __func__); return -EINVAL; } - memcpy(penv->wlan_nv_macAddr, macAddr, sizeof(penv->wlan_nv_macAddr)); - - pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + for (index = 0; index < WLAN_MAC_ADDR_SIZE; index++) { + memcpy(&penv->wlan_nv_macAddr[index], + (char *)&macAddr[index], sizeof(char)); + } + pr_info("%s: Write MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); return count; } @@ -469,10 +475,7 @@ static ssize_t wcnss_wlan_macaddr_show(struct device *dev, if (!penv) return -ENODEV; - return scnprintf(buf, PAGE_SIZE, MAC_ADDRESS_STR, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + return scnprintf(buf, PAGE_SIZE, "%pM\n", penv->wlan_nv_macAddr); } static DEVICE_ATTR(wcnss_mac_addr, S_IRUSR | S_IWUSR, @@ -566,7 +569,7 @@ void wcnss_riva_dump_pmic_regs(void) } } -/* wcnss_reset_intr() is invoked when host drivers fails to +/* wcnss_reset_fiq() is invoked when host drivers fails to * communicate with WCNSS over SMD; so logging these registers * helps to know WCNSS failure reason */ @@ -626,6 +629,10 @@ void wcnss_pronto_log_debug_regs(void) u32 reg = 0, reg2 = 0, reg3 = 0, reg4 = 0, offset_addr = 0; int i; + if (!penv || !penv->triggered || !penv->msm_wcnss_base) { + pr_info(DEVICE " WCNSS driver is not triggered by userspace\n"); + return; + } reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET; reg = readl_relaxed(reg_addr); @@ -1089,11 +1096,10 @@ int wcnss_get_mux_control(void) void __iomem *pmu_conf_reg; u32 reg = 0; - if (NULL == penv) + if (!penv || !penv->triggered || !penv->msm_wcnss_base) return 0; pmu_conf_reg = penv->msm_wcnss_base + PRONTO_PMU_OFFSET; - writel_relaxed(0, pmu_conf_reg); reg = readl_relaxed(pmu_conf_reg); reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP; writel_relaxed(reg, pmu_conf_reg); @@ -1125,7 +1131,7 @@ void wcnss_log_debug_regs_on_bite(void) } clk_rate = clk_get_rate(measure); - pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate); + pr_info("wcnss: clock frequency is: %luHz\n", clk_rate); if (clk_rate) { wcnss_pronto_log_debug_regs(); @@ -1142,19 +1148,29 @@ void wcnss_log_debug_regs_on_bite(void) #endif /* interface to reset wcnss by sending the reset interrupt */ -void wcnss_reset_intr(void) +void wcnss_reset_fiq(bool clk_chk_en) { if (wcnss_hardware_type() == WCNSS_PRONTO_HW) { - wcnss_pronto_log_debug_regs(); - if (wcnss_get_mux_control()) - wcnss_log_iris_regs(); - wmb(); - __raw_writel(1 << 16, penv->fiq_reg); + if (clk_chk_en) { + wcnss_log_debug_regs_on_bite(); + } else { + wcnss_pronto_log_debug_regs(); + if (wcnss_get_mux_control()) + wcnss_log_iris_regs(); + } + if (!wcnss_device_is_shutdown()) { + /* Insert memory barrier before writing fiq register */ + wmb(); + __raw_writel(1 << 16, penv->fiq_reg); + } else { + pr_info("%s: Block FIQ during power up sequence\n", + __func__); + } } else { wcnss_riva_log_debug_regs(); } } -EXPORT_SYMBOL(wcnss_reset_intr); +EXPORT_SYMBOL(wcnss_reset_fiq); static int wcnss_create_sysfs(struct device *dev) { @@ -1238,7 +1254,8 @@ void wcnss_disable_pc_add_req(void) if (!penv->pc_disabled) { wcnss_pm_qos_add_request(); wcnss_prevent_suspend(); - wcnss_pm_qos_update_request(WCNSS_DISABLE_PC_LATENCY); + wcnss_pm_qos_update_request(penv->wlan_config. + pc_disable_latency); penv->pc_disabled = 1; } mutex_unlock(&penv->pm_qos_mutex); @@ -1269,13 +1286,15 @@ static void wcnss_smd_notify_event(void *data, unsigned int event) schedule_work(&penv->wcnss_pm_config_work); cancel_delayed_work(&penv->wcnss_pm_qos_del_req); schedule_delayed_work(&penv->wcnss_pm_qos_del_req, 0); - + if (penv->wlan_config.is_pronto_v3 && (penv->vadc_dev)) + schedule_work(&penv->wcnss_vadc_work); break; case SMD_EVENT_CLOSE: pr_debug("wcnss: closing WCNSS SMD channel :%s", WCNSS_CTRL_CHANNEL); penv->nv_downloaded = 0; + penv->is_cbc_done = 0; break; default: @@ -1533,8 +1552,12 @@ EXPORT_SYMBOL(wcnss_get_wlan_config); int wcnss_is_hw_pronto_ver3(void) { - if (penv && penv->pdev) - return penv->wlan_config.is_pronto_v3; + if (penv && penv->pdev) { + if (penv->wlan_config.is_pronto_v3) + return penv->wlan_config.is_pronto_v3; + else if (penv->wlan_config.is_pronto_v4) + return penv->wlan_config.is_pronto_v4; + } return 0; } EXPORT_SYMBOL(wcnss_is_hw_pronto_ver3); @@ -1548,6 +1571,15 @@ int wcnss_device_ready(void) } EXPORT_SYMBOL(wcnss_device_ready); +bool wcnss_cbc_complete(void) +{ + if (penv && penv->pdev && penv->is_cbc_done && + !wcnss_device_is_shutdown()) + return true; + return false; +} +EXPORT_SYMBOL(wcnss_cbc_complete); + int wcnss_device_is_shutdown(void) { if (penv && penv->is_shutdown) @@ -1641,10 +1673,8 @@ int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE]) return -ENODEV; memcpy(mac_addr, penv->wlan_nv_macAddr, WLAN_MAC_ADDR_SIZE); - pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + pr_debug("%s: Get MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); + return 0; } EXPORT_SYMBOL(wcnss_get_wlan_mac_address); @@ -1838,8 +1868,34 @@ static int wcnss_smd_tx(void *data, int len) return ret; } +static int wcnss_get_battery_volt(int *result_uv) +{ + int rc = -1; + struct qpnp_vadc_result adc_result; + + if (!penv->vadc_dev) { + pr_err("wcnss: not setting up vadc\n"); + return rc; + } + + rc = qpnp_vadc_read(penv->vadc_dev, VBAT_SNS, &adc_result); + if (rc) { + pr_err("error reading adc channel = %d, rc = %d\n", + VBAT_SNS, rc); + return rc; + } + + pr_info("Battery mvolts phy=%lld meas=0x%llx\n", adc_result.physical, + adc_result.measurement); + *result_uv = (int)adc_result.physical; + + return 0; +} + static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) { + int rc = 0; + mutex_lock(&penv->vbat_monitor_mutex); cancel_delayed_work_sync(&penv->vbatt_work); @@ -1867,9 +1923,15 @@ static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) penv->vbat_monitor_params.low_thr, penv->vbat_monitor_params.high_thr); - qpnp_adc_tm_channel_measure(penv->adc_tm_dev, + rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev, &penv->vbat_monitor_params); - schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000)); + + if (rc) + pr_err("%s: tm setup failed: %d\n", __func__, rc); + else + schedule_delayed_work(&penv->vbatt_work, + msecs_to_jiffies(2000)); + mutex_unlock(&penv->vbat_monitor_mutex); } @@ -1884,7 +1946,12 @@ static int wcnss_setup_vbat_monitoring(void) penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD; penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD; penv->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE; - penv->vbat_monitor_params.channel = VBAT_SNS; + + if (penv->is_vsys_adc_channel) + penv->vbat_monitor_params.channel = VSYS; + else + penv->vbat_monitor_params.channel = VBAT_SNS; + penv->vbat_monitor_params.btm_ctx = (void *)penv; penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S; penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat; @@ -1895,11 +1962,32 @@ static int wcnss_setup_vbat_monitoring(void) rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev, &penv->vbat_monitor_params); if (rc) - pr_err("wcnss: tm setup failed: %d\n", rc); + pr_err("%s: tm setup failed: %d\n", __func__, rc); return rc; } +static void wcnss_send_vbatt_indication(struct work_struct *work) +{ + struct vbatt_message vbatt_msg; + int ret = 0; + + vbatt_msg.hdr.msg_type = WCNSS_VBATT_LEVEL_IND; + vbatt_msg.hdr.msg_len = sizeof(struct vbatt_message); + vbatt_msg.vbatt.threshold = WCNSS_VBATT_THRESHOLD; + + mutex_lock(&penv->vbat_monitor_mutex); + vbatt_msg.vbatt.curr_volt = penv->wlan_config.vbatt; + mutex_unlock(&penv->vbat_monitor_mutex); + pr_debug("wcnss: send curr_volt: %d to FW\n", + vbatt_msg.vbatt.curr_volt); + + ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); + if (ret < 0) + pr_err("wcnss: smd tx failed\n"); + return; +} + static void wcnss_update_vbatt(struct work_struct *work) { struct vbatt_message vbatt_msg; @@ -1991,21 +2079,23 @@ void extract_cal_data(int len) return; } + mutex_lock(&penv->dev_lock); rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr, sizeof(struct cal_data_params)); if (rc < sizeof(struct cal_data_params)) { pr_err("wcnss: incomplete cal header read from smd\n"); + mutex_unlock(&penv->dev_lock); return; } if (penv->fw_cal_exp_frag != calhdr.frag_number) { pr_err("wcnss: Invalid frgament"); - goto exit; + goto unlock_exit; } if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) { pr_err("wcnss: Invalid fragment size"); - goto exit; + goto unlock_exit; } if (penv->fw_cal_available) { @@ -2014,8 +2104,9 @@ void extract_cal_data(int len) penv->fw_cal_exp_frag++; if (calhdr.msg_flags & LAST_FRAGMENT) { penv->fw_cal_exp_frag = 0; - goto exit; + goto unlock_exit; } + mutex_unlock(&penv->dev_lock); return; } @@ -2023,7 +2114,7 @@ void extract_cal_data(int len) if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) { pr_err("wcnss: Invalid cal data size %d", calhdr.total_size); - goto exit; + goto unlock_exit; } kfree(penv->fw_cal_data); penv->fw_cal_rcvd = 0; @@ -2031,11 +2122,10 @@ void extract_cal_data(int len) GFP_KERNEL); if (penv->fw_cal_data == NULL) { smd_read(penv->smd_ch, NULL, calhdr.frag_size); - goto exit; + goto unlock_exit; } } - mutex_lock(&penv->dev_lock); if (penv->fw_cal_rcvd + calhdr.frag_size > MAX_CALIBRATED_DATA_SIZE) { pr_err("calibrated data size is more than expected %d", @@ -2070,8 +2160,6 @@ void extract_cal_data(int len) unlock_exit: mutex_unlock(&penv->dev_lock); - -exit: wcnss_send_cal_rsp(fw_status); return; } @@ -2183,6 +2271,8 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) fw_status = wcnss_fw_status(); pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n", fw_status); + if (fw_status != WAIT_FOR_CBC_IND) + penv->is_cbc_done = 1; wcnss_setup_vbat_monitoring(); break; @@ -2192,6 +2282,10 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n", fw_status); break; + case WCNSS_CBC_COMPLETE_IND: + penv->is_cbc_done = 1; + pr_debug("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n"); + break; case WCNSS_CALDATA_UPLD_REQ: extract_cal_data(len); @@ -2543,66 +2637,67 @@ static int wcnss_ctrl_open(struct inode *inode, struct file *file) return rc; } - -void process_usr_ctrl_cmd(u8 *buf, size_t len) +static ssize_t wcnss_ctrl_write(struct file *fp, const char __user + *user_buffer, size_t count, loff_t *position) { - u16 cmd = buf[0] << 8 | buf[1]; + int rc = 0; + u16 cmd; + u8 buf[WCNSS_MAX_CMD_LEN]; - switch (cmd) { + if (!penv || !penv->ctrl_device_opened || + WCNSS_MAX_CMD_LEN < count || WCNSS_MIN_CMD_LEN > count) + return -EFAULT; + mutex_lock(&penv->ctrl_lock); + rc = copy_from_user(buf, user_buffer, count); + if (rc) { + pr_err("%s: Failed to copy ctrl data\n", __func__); + goto exit; + } + + cmd = buf[0] << 8 | buf[1]; + switch (cmd) { case WCNSS_USR_SERIAL_NUM: - if (WCNSS_MIN_SERIAL_LEN > len) { + if (WCNSS_MIN_SERIAL_LEN > count) { pr_err("%s: Invalid serial number\n", __func__); - return; + rc = -EINVAL; + goto exit; } penv->serial_number = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5]; break; case WCNSS_USR_HAS_CAL_DATA: - if (1 < buf[2]) - pr_err("%s: Invalid data for cal %d\n", __func__, - buf[2]); + if (buf[2] > 1) { + pr_err("%s: Invalid cal data %d\n", __func__, buf[2]); + rc = -EINVAL; + goto exit; + } has_calibrated_data = buf[2]; break; case WCNSS_USR_WLAN_MAC_ADDR: - memcpy(&penv->wlan_nv_macAddr, &buf[2], - sizeof(penv->wlan_nv_macAddr)); + if ((count - WCNSS_CMD_INFO_LEN) != WLAN_MAC_ADDR_SIZE) { + pr_err("%s: Invalid Mac addr %d\n", __func__, buf[2]); + rc = -EINVAL; + goto exit; + } - pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__, - penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1], - penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3], - penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]); + memcpy(&penv->wlan_nv_macAddr, &buf[2], + sizeof(penv->wlan_nv_macAddr)); + pr_debug("%s:MAC Addr: %pM\n", __func__, penv->wlan_nv_macAddr); break; - default: pr_err("%s: Invalid command %d\n", __func__, cmd); + rc = -EINVAL; break; } -} - -static ssize_t wcnss_ctrl_write(struct file *fp, const char __user - *user_buffer, size_t count, loff_t *position) -{ - int rc = 0; - u8 buf[WCNSS_MAX_CMD_LEN]; - - if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count - || WCNSS_MIN_CMD_LEN > count) - return -EFAULT; - - mutex_lock(&penv->ctrl_lock); - rc = copy_from_user(buf, user_buffer, count); - if (0 == rc) - process_usr_ctrl_cmd(buf, count); +exit: mutex_unlock(&penv->ctrl_lock); - return rc; } - static const struct file_operations wcnss_ctrl_fops = { .owner = THIS_MODULE, .open = wcnss_ctrl_open, @@ -2619,10 +2714,12 @@ static int wcnss_trigger_config(struct platform_device *pdev) { int ret; + int rc; struct qcom_wcnss_opts *pdata; struct resource *res; int is_pronto_vt; int is_pronto_v3; + int is_pronto_v4; int pil_retry = 0; int has_pronto_hw = of_property_read_bool(pdev->dev.of_node, "qcom,has-pronto-hw"); @@ -2633,11 +2730,23 @@ wcnss_trigger_config(struct platform_device *pdev) is_pronto_v3 = of_property_read_bool(pdev->dev.of_node, "qcom,is-pronto-v3"); + is_pronto_v4 = of_property_read_bool(pdev->dev.of_node, + "qcom,is-pronto-v4"); + + penv->is_vsys_adc_channel = of_property_read_bool(pdev->dev.of_node, + "qcom,has-vsys-adc-channel"); + if (of_property_read_u32(pdev->dev.of_node, "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) { penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT; } + if (of_property_read_u32(pdev->dev.of_node, + "qcom,pc-disable-latency", + &penv->wlan_config.pc_disable_latency)) { + penv->wlan_config.pc_disable_latency = WCNSS_DISABLE_PC_LATENCY; + } + /* make sure we are only triggered once */ if (penv->triggered) return 0; @@ -2657,6 +2766,7 @@ wcnss_trigger_config(struct platform_device *pdev) penv->wlan_config.use_48mhz_xo = has_48mhz_xo; penv->wlan_config.is_pronto_vt = is_pronto_vt; penv->wlan_config.is_pronto_v3 = is_pronto_v3; + penv->wlan_config.is_pronto_v4 = is_pronto_v4; if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) { has_autodetect_xo = of_property_read_bool(pdev->dev.of_node, @@ -2951,6 +3061,23 @@ wcnss_trigger_config(struct platform_device *pdev) penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED; } + if (penv->wlan_config.is_pronto_v3) { + penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss"); + + if (IS_ERR(penv->vadc_dev)) { + pr_err("%s: vadc get failed\n", __func__); + penv->vadc_dev = NULL; + } else { + rc = wcnss_get_battery_volt(&penv->wlan_config.vbatt); + INIT_WORK(&penv->wcnss_vadc_work, + wcnss_send_vbatt_indication); + + if (rc < 0) + pr_err("Failed to get battery voltage with error= %d\n", + rc); + } + } + do { /* trigger initialization of the WCNSS */ penv->pil = subsystem_get(WCNSS_PIL_DEVICE); @@ -2963,7 +3090,7 @@ wcnss_trigger_config(struct platform_device *pdev) } while (pil_retry++ < WCNSS_MAX_PIL_RETRY && IS_ERR(penv->pil)); if (IS_ERR(penv->pil)) { - wcnss_reset_intr(); + wcnss_reset_fiq(false); if (penv->wcnss_notif_hdle) subsys_notif_unregister_notifier(penv->wcnss_notif_hdle, &wnb); @@ -2973,6 +3100,10 @@ wcnss_trigger_config(struct platform_device *pdev) /* Remove pm_qos request */ wcnss_disable_pc_remove_req(); + if (of_property_read_bool(pdev->dev.of_node, + "qcom,wlan-indication-enabled")) + wcnss_en_wlan_led_trigger(); + return 0; fail_ioremap2: @@ -2993,6 +3124,62 @@ fail_gpio_res: return ret; } +/* wlan prop driver cannot invoke cancel_work_sync + * function directly, so to invoke this function it + * call wcnss_flush_work function + */ +void wcnss_flush_work(struct work_struct *work) +{ + struct work_struct *cnss_work = work; + if (cnss_work != NULL) + cancel_work_sync(cnss_work); +} +EXPORT_SYMBOL(wcnss_flush_work); + +/* wlan prop driver cannot invoke show_stack + * function directly, so to invoke this function it + * call wcnss_dump_stack function + */ +void wcnss_dump_stack(struct task_struct *task) +{ + show_stack(task, NULL); +} +EXPORT_SYMBOL(wcnss_dump_stack); + +/* wlan prop driver cannot invoke cancel_delayed_work_sync + * function directly, so to invoke this function it call + * wcnss_flush_delayed_work function + */ +void wcnss_flush_delayed_work(struct delayed_work *dwork) +{ + struct delayed_work *cnss_dwork = dwork; + if (cnss_dwork != NULL) + cancel_delayed_work_sync(cnss_dwork); +} +EXPORT_SYMBOL(wcnss_flush_delayed_work); + +/* wlan prop driver cannot invoke INIT_WORK function + * directly, so to invoke this function call + * wcnss_init_work function. + */ +void wcnss_init_work(struct work_struct *work , void *callbackptr) +{ + if (work && callbackptr) + INIT_WORK(work, callbackptr); +} +EXPORT_SYMBOL(wcnss_init_work); + +/* wlan prop driver cannot invoke INIT_DELAYED_WORK + * function directly, so to invoke this function + * call wcnss_init_delayed_work function. + */ +void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr) +{ + if (dwork && callbackptr) + INIT_DELAYED_WORK(dwork, callbackptr); +} +EXPORT_SYMBOL(wcnss_init_delayed_work); + static int wcnss_node_open(struct inode *inode, struct file *file) { struct platform_device *pdev; @@ -3148,6 +3335,7 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, wcnss_disable_pc_add_req(); schedule_delayed_work(&penv->wcnss_pm_qos_del_req, msecs_to_jiffies(WCNSS_PM_QOS_TIMEOUT)); + penv->is_shutdown = 1; wcnss_log_debug_regs_on_bite(); } else if (code == SUBSYS_POWERUP_FAILURE) { if (pdev && pwlanconfig) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a1db958df4a4b6f517599ecb123dffcd283dae9d..8e85ce1ecdfb654234db6ea042af7d42432de837 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -820,7 +820,6 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np, struct sk_buff *skb, struct sk_buff_head *list) { - struct skb_shared_info *shinfo = skb_shinfo(skb); RING_IDX cons = np->rx.rsp_cons; struct sk_buff *nskb; @@ -829,15 +828,16 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np, RING_GET_RESPONSE(&np->rx, ++cons); skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0]; - if (shinfo->nr_frags == MAX_SKB_FRAGS) { + if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; BUG_ON(pull_to <= skb_headlen(skb)); __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); } - BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS); + BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS); - skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag), + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + skb_frag_page(nfrag), rx->offset, rx->status, PAGE_SIZE); skb_shinfo(nskb)->nr_frags = 0; diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c index c6ea9dbd373b81d1974bd3b0442f5a1b2e1399a3..ee42b833a8c214107551476ec2563d0afadc6d89 100644 --- a/drivers/platform/msm/ipa/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/rmnet_ipa.c @@ -2622,10 +2622,8 @@ static int __init ipa_wwan_init(void) atomic_set(&is_ssr, 0); mutex_init(&add_mux_channel_lock); - ipa_qmi_init(); - mutex_init(&add_mux_channel_lock); /* Register for Modem SSR */ subsys = subsys_notif_register_notifier(SUBSYS_MODEM, &ssr_notifier); if (!IS_ERR(subsys)) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 48755ffb4b7b0b1346cecf266187851c9b39587b..172dd9ea31f3e30ccbb731c199e7734644139da7 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -244,6 +244,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(vfloat_mv), POWER_SUPPLY_ATTR(fv_cmp_cfg), POWER_SUPPLY_ATTR(batt_aging), + POWER_SUPPLY_ATTR(soc_reporting_ready), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/qcom/lpm-stats.c b/drivers/power/qcom/lpm-stats.c index 321e13c2b7ea39fec72ea0d1a71a597a94a5ca03..f4f22007b4cbe83dbfb8f5e918342e010947610a 100644 --- a/drivers/power/qcom/lpm-stats.c +++ b/drivers/power/qcom/lpm-stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2018, The Linux Foundation. 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 and @@ -590,11 +590,14 @@ static void cleanup_stats(struct lpm_stats *stats) { struct list_head *centry = NULL; struct lpm_stats *pos = NULL; + struct lpm_stats *n = NULL; centry = &stats->child; - list_for_each_entry_reverse(pos, centry, sibling) { - if (!list_empty(&pos->child)) + list_for_each_entry_safe_reverse(pos, n, centry, sibling) { + if (!list_empty(&pos->child)) { cleanup_stats(pos); + continue; + } list_del_init(&pos->child); diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c index 8d5e61bc7bdaac0af9ab1f2b81b681f25182918d..a6c463fd7855b0e1b965a83e0bc204595238b7bc 100644 --- a/drivers/power/qpnp-charger.c +++ b/drivers/power/qpnp-charger.c @@ -3452,14 +3452,15 @@ qpnp_chg_regulator_boost_enable(struct regulator_dev *rdev) pr_err("failed to write SEC_ACCESS rc=%d\n", rc); return rc; } - - rc = qpnp_chg_masked_write(chip, - chip->usb_chgpth_base + COMP_OVR1, - 0xFF, - 0x2F, 1); - if (rc) { - pr_err("failed to write COMP_OVR1 rc=%d\n", rc); - return rc; + if (chip->type != SMBBP) { + rc = qpnp_chg_masked_write(chip, + chip->usb_chgpth_base + COMP_OVR1, + 0xFF, + 0x2F, 1); + if (rc) { + pr_err("failed to write COMP_OVR1 rc=%d\n", rc); + return rc; + } } } @@ -3558,16 +3559,16 @@ qpnp_chg_regulator_boost_disable(struct regulator_dev *rdev) pr_err("failed to write SEC_ACCESS rc=%d\n", rc); return rc; } - - rc = qpnp_chg_masked_write(chip, - chip->usb_chgpth_base + COMP_OVR1, - 0xFF, - 0x00, 1); - if (rc) { - pr_err("failed to write COMP_OVR1 rc=%d\n", rc); - return rc; + if (chip->type != SMBBP) { + rc = qpnp_chg_masked_write(chip, + chip->usb_chgpth_base + COMP_OVR1, + 0xFF, + 0x00, 1); + if (rc) { + pr_err("failed to write COMP_OVR1 rc=%d\n", rc); + return rc; + } } - usleep(1000); qpnp_chg_usb_suspend_enable(chip, 0); @@ -3778,7 +3779,7 @@ qpnp_chg_adjust_vddmax(struct qpnp_chg_chip *chip, int vbat_mv) qpnp_chg_set_appropriate_vddmax(chip); } -#define CONSECUTIVE_COUNT 3 +#define CONSECUTIVE_COUNT 10 #define VBATDET_MAX_ERR_MV 50 static void qpnp_eoc_work(struct work_struct *work) diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index 93c35d203cb7a3c47854c1cc9e4feb8b479a1239..8e3c958e714b2a05ecdaf3ada6d11cbfce0f4073 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -1110,7 +1110,10 @@ static int fg_mem_masked_write(struct fg_chip *chip, u16 addr, static int soc_to_setpoint(int soc) { - return DIV_ROUND_CLOSEST(soc * 255, 100); + if (soc == 0) + return 1; + else + return DIV_ROUND_CLOSEST(soc * 255, 100); } static void batt_to_setpoint_adc(int vbatt_mv, u8 *data) @@ -2340,6 +2343,7 @@ static enum power_supply_property fg_power_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MIN, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNT_ID, + POWER_SUPPLY_PROP_SOC_REPORTING_READY, #ifdef CONFIG_QPNP_FG_EXTENSION POWER_SUPPLY_PROP_BATT_AGING, #endif @@ -2435,6 +2439,9 @@ static int fg_power_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_NOW_RAW: val->intval = get_sram_prop_now(chip, FG_DATA_CC_CHARGE); break; + case POWER_SUPPLY_PROP_SOC_REPORTING_READY: + val->intval = !!chip->profile_loaded; + break; #ifdef CONFIG_QPNP_FG_EXTENSION case POWER_SUPPLY_PROP_BATT_AGING: val->intval = chip->somc_params.batt_aging; @@ -2717,20 +2724,20 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) #ifdef CONFIG_QPNP_FG_EXTENSION max_inc_val = chip->learning_data.max_increment ? - chip->learning_data.learned_cc_uah + (int64_t)chip->learning_data.learned_cc_uah * (1000 + chip->learning_data.max_increment) : ((int64_t)chip->nom_cap_uah) * 1000; #else - max_inc_val = chip->learning_data.learned_cc_uah + max_inc_val = (int64_t)chip->learning_data.learned_cc_uah * (1000 + chip->learning_data.max_increment); #endif do_div(max_inc_val, 1000); - min_dec_val = chip->learning_data.learned_cc_uah + min_dec_val = (int64_t)chip->learning_data.learned_cc_uah * (1000 - chip->learning_data.max_decrement); do_div(min_dec_val, 1000); - old_cap = chip->learning_data.learned_cc_uah; + old_cap = (int64_t)chip->learning_data.learned_cc_uah; if (chip->learning_data.cc_uah > max_inc_val) chip->learning_data.learned_cc_uah = max_inc_val; else if (chip->learning_data.cc_uah < min_dec_val) @@ -5397,7 +5404,7 @@ static int fg_common_hw_init(struct fg_chip *chip) settings[FG_MEM_DELTA_SOC].offset); #else rc = fg_mem_masked_write(chip, settings[FG_MEM_DELTA_SOC].address, 0xFF, - soc_to_setpoint(settings[FG_MEM_DELTA_SOC].value), + settings[FG_MEM_DELTA_SOC].value == 1 ? 1 : soc_to_setpoint(settings[FG_MEM_DELTA_SOC].value), settings[FG_MEM_DELTA_SOC].offset); #endif @@ -5973,8 +5980,8 @@ static int fg_suspend(struct device *dev) if (!chip->sw_rbias_ctrl) return 0; - cancel_delayed_work(&chip->update_temp_work); - cancel_delayed_work(&chip->update_sram_data); + cancel_delayed_work_sync(&chip->update_temp_work); + cancel_delayed_work_sync(&chip->update_sram_data); return 0; } diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index b9cc66d298bc97256da5a2b11d25ce386ee6118b..3c69b1f6c3176e30e9908d768ed5366508310205 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -1674,7 +1674,7 @@ static int smbchg_set_usb_current_max(struct smbchg_chip *chip, } chip->usb_max_current_ma = 500; } - if (current_ma == CURRENT_900_MA) { + if ((current_ma <= CURRENT_150_MA) || (current_ma == CURRENT_500_MA) || (current_ma == CURRENT_900_MA)) { // AP: Fast charge for USB rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, CFG_USB_2_3_SEL_BIT, CFG_USB_3); @@ -2133,6 +2133,8 @@ static void smbchg_parallel_usb_enable(struct smbchg_chip *chip) rc); goto disable_parallel; } + rc = power_supply_set_voltage_limit(chip->usb_psy, + (chip->vfloat_mv + 50) * 1000); chip->target_fastchg_current_ma = chip->cfg_fastchg_current_ma / 2; smbchg_set_fastchg_current(chip, chip->target_fastchg_current_ma); pval.intval = chip->target_fastchg_current_ma * 1000; @@ -2906,8 +2908,11 @@ static int smbchg_float_voltage_set(struct smbchg_chip *chip, int vfloat_mv) if (rc) dev_err(chip->dev, "Couldn't set float voltage rc = %d\n", rc); - else + else { chip->vfloat_mv = vfloat_mv; + power_supply_set_voltage_limit(chip->usb_psy, + chip->vfloat_mv * 1000); + } return rc; } @@ -6905,6 +6910,7 @@ static int smbchg_probe(struct spmi_device *spmi) power_supply_set_present(chip->usb_psy, chip->usb_present); + update_usb_status(chip, is_usb_present(chip), false); dump_regs(chip); create_debugfs_entries(chip); dev_info(chip->dev, diff --git a/drivers/power/qpnp-smbcharger_extension.c b/drivers/power/qpnp-smbcharger_extension.c index 1167428e308dcf4678b96a239494e989396aba26..f16fc9c8f024f89b7d73da64df6310695238e888 100644 --- a/drivers/power/qpnp-smbcharger_extension.c +++ b/drivers/power/qpnp-smbcharger_extension.c @@ -1333,7 +1333,7 @@ static void somc_chg_aicl_reset_params(void) } #define AICL_PERIOD_MS 200 -#define AICL_WAKE_PERIOD (10 * HZ) +#define AICL_WAKE_PERIOD (10000) static void somc_chg_aicl_work(struct work_struct *work) { if (!*chg_params->usb_present) @@ -1353,7 +1353,8 @@ static void somc_chg_aicl_work(struct work_struct *work) *chg_params->usb_suspended, chg_params->last_therm_lvl_sel, *chg_params->thermal.lvl_sel); - wake_lock_timeout(&chg_params->aicl_wakelock, AICL_WAKE_PERIOD); + wake_lock_timeout(&chg_params->aicl_wakelock, + msecs_to_jiffies(AICL_WAKE_PERIOD)); somc_chg_aicl_reset_params(); somc_chg_set_thermal_limited_iusb_max(IUSBMAX_MIN_0MA); chg_params->last_usb_target_current_ma = @@ -1409,7 +1410,7 @@ void somc_chg_aicl_start_work(void) *chg_params->usb_present) { pr_info("Start aicl worker\n"); wake_lock_timeout(&chg_params->aicl_wakelock, - AICL_WAKE_PERIOD); + msecs_to_jiffies(AICL_WAKE_PERIOD)); somc_chg_set_thermal_limited_iusb_max(IUSBMAX_MIN_0MA); somc_chg_forced_iusb_dec_clear_params(); schedule_delayed_work(&chg_params->aicl_work, @@ -2405,6 +2406,11 @@ static unsigned int *somc_chg_therm_create_tb(struct device *dev, if (of_find_property(node, thermal, &thermal_levels)) { thermal_size = thermal_levels / sizeof(int); + if (!thermal_levels || !thermal_size) { + dev_err(dev, "Invalid thermal parameters\n"); + *size = -EINVAL; + return NULL; + } thermal_tb = devm_kzalloc(dev, thermal_levels, GFP_KERNEL); if (thermal_tb == NULL) { dev_err(dev, "thermal mitigation kzalloc() failed.\n"); @@ -2849,10 +2855,11 @@ void somc_batfet_open(struct device *dev, bool open) } } -#define UNPLUG_WAKE_PERIOD (3 * HZ) +#define UNPLUG_WAKE_PERIOD (3000) void somc_unplug_wakelock(void) { - wake_lock_timeout(&chg_params->unplug_wakelock, UNPLUG_WAKE_PERIOD); + wake_lock_timeout(&chg_params->unplug_wakelock, + msecs_to_jiffies(UNPLUG_WAKE_PERIOD)); } #define VFLOAT_CMP_CFG_REG 0xF5 diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 32221cb0cbe713622c8773822fc1f6e5be91e49d..0cf0f65eb037ad20ad750dac4c5cbf0b1ab4f73c 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -694,7 +694,7 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) { struct pwm_device **ptr, *pwm; - ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); @@ -724,7 +724,7 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, { struct pwm_device **ptr, *pwm; - ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 4ca07a589cf32789eb870ddd1f00d83799567142..c3eb411c89f95b6600ead84d52411ccdf540ca4c 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2015, 2018, The Linux Foundation. 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 and @@ -404,19 +404,19 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn, mutex_unlock(&svc->m_lock); return NULL; } - if (!svc->port_cnt && !svc->svc_cnt) + if (!svc->svc_cnt) clnt->svc_cnt++; svc->port_cnt++; svc->port_fn[temp_port] = svc_fn; svc->port_priv[temp_port] = priv; + svc->svc_cnt++; } else { if (!svc->fn) { - if (!svc->port_cnt && !svc->svc_cnt) + if (!svc->svc_cnt) clnt->svc_cnt++; svc->fn = svc_fn; - if (svc->port_cnt) - svc->svc_cnt++; svc->priv = priv; + svc->svc_cnt++; } } @@ -621,24 +621,17 @@ int apr_deregister(void *handle) client_id = svc->client_id; clnt = &client[dest_id][client_id]; - if (svc->port_cnt > 0 || svc->svc_cnt > 0) { + if (svc->svc_cnt > 0) { if (svc->port_cnt) svc->port_cnt--; - else if (svc->svc_cnt) - svc->svc_cnt--; - if (!svc->port_cnt && !svc->svc_cnt) { + svc->svc_cnt--; + if (!svc->svc_cnt) { client[dest_id][client_id].svc_cnt--; - svc->need_reset = 0x0; - } - } else if (client[dest_id][client_id].svc_cnt > 0) { - client[dest_id][client_id].svc_cnt--; - if (!client[dest_id][client_id].svc_cnt) { - svc->need_reset = 0x0; pr_debug("%s: service is reset %pK\n", __func__, svc); } } - if (!svc->port_cnt && !svc->svc_cnt) { + if (!svc->svc_cnt) { svc->priv = NULL; svc->id = 0; svc->fn = NULL; diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index c3c2144d0d78d573aa2bddbf8035eab24b2e3ffc..126c5cab73e5ed03ee71d0015e8d832a609c54d9 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \ - ion_carveout_heap.o ion_chunk_heap.o + ion_carveout_heap.o ion_chunk_heap.o ion_system_secure_heap.o obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o obj-$(CONFIG_ION_TEST) += ion_test.o ifdef CONFIG_COMPAT diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 298f28f9978255be6428cb25e51f853fa93dfba5..eabe1b7a1e72807d8df6680dcda34dbf6e2e32ac 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -228,10 +228,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, "heap->ops->map_dma should return ERR_PTR on error")) table = ERR_PTR(-EINVAL); if (IS_ERR(table)) { - heap->ops->free(buffer); - kfree(buffer); - return ERR_PTR(PTR_ERR(table)); + ret = -EINVAL; + goto err1; } + buffer->sg_table = table; if (ion_buffer_fault_user_mappings(buffer)) { int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; @@ -241,7 +241,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, buffer->pages = vmalloc(sizeof(struct page *) * num_pages); if (!buffer->pages) { ret = -ENOMEM; - goto err1; + goto err; } for_each_sg(table->sgl, sg, table->nents, i) { @@ -250,9 +250,6 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, for (j = 0; j < sg->length / PAGE_SIZE; j++) buffer->pages[k++] = page++; } - - if (ret) - goto err; } mutex_init(&buffer->lock); @@ -276,10 +273,8 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, err: heap->ops->unmap_dma(heap, buffer); - heap->ops->free(buffer); err1: - if (buffer->pages) - vfree(buffer->pages); + heap->ops->free(buffer); err2: kfree(buffer); return ERR_PTR(ret); @@ -572,7 +567,6 @@ static struct ion_handle *__ion_alloc(struct ion_client *client, size_t len, struct ion_buffer *buffer = NULL; struct ion_heap *heap; int ret; - unsigned long secure_allocation = flags & ION_FLAG_SECURE; const unsigned int MAX_DBG_STR_LEN = 64; char dbg_str[MAX_DBG_STR_LEN]; unsigned int dbg_str_idx = 0; @@ -605,10 +599,6 @@ static struct ion_handle *__ion_alloc(struct ion_client *client, size_t len, /* if the caller didn't specify this heap id */ if (!((1 << heap->id) & heap_id_mask)) continue; - /* Do not allow un-secure heap if secure is specified */ - if (secure_allocation && - !ion_heap_allow_secure_allocation(heap->type)) - continue; trace_ion_alloc_buffer_start(client->name, heap->name, len, heap_id_mask, flags); buffer = ion_buffer_create(heap, dev, len, align, flags); @@ -1029,6 +1019,7 @@ void ion_client_destroy(struct ion_client *client) struct rb_node *n; pr_debug("%s: %d\n", __func__, __LINE__); + mutex_lock(&client->lock); while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); @@ -1036,6 +1027,7 @@ void ion_client_destroy(struct ion_client *client) } idr_destroy(&client->idr); + mutex_unlock(&client->lock); down_write(&dev->lock); if (client->task) @@ -1095,6 +1087,13 @@ int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle, } EXPORT_SYMBOL(ion_handle_get_size); +/** + * ion_sg_table - get an sg_table for the buffer + * + * NOTE: most likely you should NOT being using this API. + * You should be using Ion as a DMA Buf exporter and using + * the sg_table returned by dma_buf_map_attachment. + */ struct sg_table *ion_sg_table(struct ion_client *client, struct ion_handle *handle) { @@ -1145,6 +1144,30 @@ err0: return ERR_PTR(ret); } +static struct sg_table *ion_dupe_sg_table(struct sg_table *orig_table) +{ + int ret, i; + struct scatterlist *sg, *sg_orig; + struct sg_table *table; + + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!table) + return NULL; + + ret = sg_alloc_table(table, orig_table->nents, GFP_KERNEL); + if (ret) { + kfree(table); + return NULL; + } + + sg_orig = orig_table->sgl; + for_each_sg(table->sgl, sg, table->nents, i) { + memcpy(sg, sg_orig, sizeof(*sg)); + sg_orig = sg_next(sg_orig); + } + return table; +} + static void ion_buffer_sync_for_device(struct ion_buffer *buffer, struct device *dev, enum dma_data_direction direction); @@ -1154,15 +1177,22 @@ static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, { struct dma_buf *dmabuf = attachment->dmabuf; struct ion_buffer *buffer = dmabuf->priv; + struct sg_table *table; + + table = ion_dupe_sg_table(buffer->sg_table); + if (!table) + return NULL; ion_buffer_sync_for_device(buffer, attachment->dev, direction); - return buffer->sg_table; + return table; } static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, struct sg_table *table, enum dma_data_direction direction) { + sg_free_table(table); + kfree(table); } void ion_pages_sync_for_device(struct device *dev, struct page *page, @@ -1491,6 +1521,11 @@ static int ion_sync_for_device(struct ion_client *client, int fd) } buffer = dmabuf->priv; + if ((buffer->flags & ION_FLAG_SECURE) || (get_secure_vmid(buffer->flags) > 0)) { + pr_err("%s: cannot sync a secure dmabuf\n", __func__); + dma_buf_put(dmabuf); + return -EINVAL; + } dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, buffer->sg_table->nents, DMA_BIDIRECTIONAL); dma_buf_put(dmabuf); diff --git a/drivers/staging/android/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c index ba3adb7666cd23d8b29564bbea44a5e60d0266ef..a03092078ca7d544d9c723fd00331d6a4014aca5 100644 --- a/drivers/staging/android/ion/ion_cma_secure_heap.c +++ b/drivers/staging/android/ion/ion_cma_secure_heap.c @@ -654,7 +654,8 @@ static int ion_secure_cma_allocate(struct ion_heap *heap, struct ion_secure_cma_buffer_info *buf = NULL; unsigned long allow_non_contig = flags & ION_FLAG_ALLOW_NON_CONTIG; - if (!secure_allocation) { + if (!secure_allocation && + !ion_heap_allow_secure_allocation(heap->type)) { pr_err("%s: non-secure allocation disallowed from heap %s %lx\n", __func__, heap->name, flags); return -ENOMEM; diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 2bd59fbfb5f6fa3078befe4abf235bbb0185fdcd..c2bf067833f48f34666f2c388a46dfbb8ded508c 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "ion_priv.h" static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) @@ -52,7 +53,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { - spin_lock(&pool->lock); + mutex_lock(&pool->mutex); if (PageHighMem(page)) { list_add_tail(&page->lru, &pool->high_items); pool->high_count++; @@ -60,7 +61,7 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) list_add_tail(&page->lru, &pool->low_items); pool->low_count++; } - spin_unlock(&pool->lock); + mutex_unlock(&pool->mutex); return 0; } @@ -90,13 +91,13 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool) *from_pool = true; - spin_lock(&pool->lock); - if (pool->high_count) - page = ion_page_pool_remove(pool, true); - else if (pool->low_count) - page = ion_page_pool_remove(pool, false); - spin_unlock(&pool->lock); - + if (mutex_trylock(&pool->mutex)) { + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + mutex_unlock(&pool->mutex); + } if (!page) { page = ion_page_pool_alloc_pages(pool); *from_pool = false; @@ -137,22 +138,16 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, for (i = 0; i < nr_to_scan; i++) { struct page *page; - /* - * If the lock is taken, it's better to let other shrinkers - * do their job, rather than spin here. We'll catch up - * next time. - */ - if (!spin_trylock(&pool->lock)) - break; + mutex_lock(&pool->mutex); if (pool->low_count) { page = ion_page_pool_remove(pool, false); } else if (high && pool->high_count) { page = ion_page_pool_remove(pool, true); } else { - spin_unlock(&pool->lock); + mutex_unlock(&pool->mutex); break; } - spin_unlock(&pool->lock); + mutex_unlock(&pool->mutex); ion_page_pool_free_pages(pool, page); } @@ -171,7 +166,7 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) INIT_LIST_HEAD(&pool->high_items); pool->gfp_mask = gfp_mask; pool->order = order; - spin_lock_init(&pool->lock); + mutex_init(&pool->mutex); plist_node_init(&pool->list, order); return pool; diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 57c33c13bbde8fc223858e2660fda1e8f3f3490d..371b8a7ad5d2317c03cdfc9bc8e95474061daef8 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2014,2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -51,8 +51,11 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @lock: protects the buffers cnt fields * @kmap_cnt: number of times the buffer is mapped to the kernel * @vaddr: the kenrel mapping if kmap_cnt is not zero - * @dmap_cnt: number of times the buffer is mapped for dma - * @sg_table: the sg table for the buffer if dmap_cnt is not zero + * @sg_table: the sg table for the buffer. Note that if you need + * an sg_table for this buffer, you should likely be + * using Ion as a DMA Buf exporter and using + * dma_buf_map_attachment rather than trying to use this + * field directly. * @pages: flat array of pages in the buffer -- used by fault * handler and only valid for buffers that are faulted in * @vmas: list of vma's mapping this buffer @@ -80,7 +83,6 @@ struct ion_buffer { struct mutex lock; int kmap_cnt; void *vaddr; - int dmap_cnt; struct sg_table *sg_table; struct page **pages; struct list_head vmas; @@ -257,6 +259,7 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *, int ion_heap_buffer_zero(struct ion_buffer *buffer); int msm_ion_heap_high_order_page_zero(struct page *page, int order); +struct ion_heap *get_ion_heap(int heap_id); int msm_ion_heap_buffer_zero(struct ion_buffer *buffer); int msm_ion_heap_pages_zero(struct page **pages, int num_pages); int msm_ion_heap_alloc_pages_mem(struct pages_mem *pages_mem); @@ -352,8 +355,16 @@ void ion_carveout_heap_destroy(struct ion_heap *); struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *); void ion_chunk_heap_destroy(struct ion_heap *); +#ifdef CONFIG_CMA struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *); void ion_cma_heap_destroy(struct ion_heap *); +#else +static inline struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *h) +{ + return NULL; +} +static inline void ion_cma_heap_destroy(struct ion_heap *h) {} +#endif /** * kernel api to allocate/free from carveout -- used when carveout is @@ -382,7 +393,7 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, * @low_count: number of lowmem items in the pool * @high_items: list of highmem items * @low_items: list of lowmem items - * @lock: lock protecting this struct and especially the count + * @mutex: lock protecting this struct and especially the count * item list * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool @@ -398,7 +409,7 @@ struct ion_page_pool { int low_count; struct list_head high_items; struct list_head low_items; - spinlock_t lock; + struct mutex mutex; gfp_t gfp_mask; unsigned int order; struct plist_node list; diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 144c3294959e572b74ca76ebf791a6766937fd3c..179182c6441f6484abd504fc14588baaadceb26c 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -35,7 +35,7 @@ static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN | static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN); #ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS -static const unsigned int orders[] = {9, 8, 4, 0}; +static const unsigned int orders[] = {4, 0}; #else static const unsigned int orders[] = {0}; #endif @@ -411,13 +411,12 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, pool->low_count, pool->order, (1 << pool->order) * PAGE_SIZE * pool->low_count); - } else { - uncached_total += (1 << pool->order) * PAGE_SIZE * - pool->high_count; - uncached_total += (1 << pool->order) * PAGE_SIZE * - pool->low_count; } + uncached_total += (1 << pool->order) * PAGE_SIZE * + pool->high_count; + uncached_total += (1 << pool->order) * PAGE_SIZE * + pool->low_count; } for (i = 0; i < num_orders; i++) { @@ -432,17 +431,29 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, pool->low_count, pool->order, (1 << pool->order) * PAGE_SIZE * pool->low_count); - } else { - cached_total += (1 << pool->order) * PAGE_SIZE * - pool->high_count; - cached_total += (1 << pool->order) * PAGE_SIZE * - pool->low_count; } + + cached_total += (1 << pool->order) * PAGE_SIZE * + pool->high_count; + cached_total += (1 << pool->order) * PAGE_SIZE * + pool->low_count; } - if (!use_seq) - pr_info("uncached pool total = %lu cached pool total %lu\n", + if (use_seq) { + seq_puts(s, "--------------------------------------------\n"); + seq_printf(s, "uncached pool = %lu cached pool = %lu\n", uncached_total, cached_total); + seq_printf(s, "pool total (uncached + cached) = %lu\n", + uncached_total + cached_total); + seq_puts(s, "--------------------------------------------\n"); + } else { + pr_info("-------------------------------------------------\n"); + pr_info("uncached pool = %lu cached pool = %lu\n", + uncached_total, cached_total); + pr_info("pool total (uncached + cached) = %lu\n", + uncached_total + cached_total); + pr_info("-------------------------------------------------\n"); + } return 0; } diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c new file mode 100644 index 0000000000000000000000000000000000000000..7419c0c79fd2b4911f62180e0f1d5b1b28b32f35 --- /dev/null +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -0,0 +1,211 @@ +/* + * + * Copyright (c) 2014-2015, 2018 The Linux Foundation. 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 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include "ion.h" +#include "ion_priv.h" + +struct ion_system_secure_heap { + struct ion_heap *sys_heap; + struct ion_heap heap; +}; + +#define VMID_HLOS 0x3 +#define VMID_CP_TOUCH 0x8 +#define VMID_CP_BITSTREAM 0x9 +#define VMID_CP_PIXEL 0xA +#define VMID_CP_NON_PIXEL 0xB +#define VMID_CP_CAMERA 0xD +#define VMID_HLOS_FREE 0xE + +static bool is_cp_flag_present(unsigned long flags) +{ + return flags && (ION_FLAG_CP_TOUCH || + ION_FLAG_CP_BITSTREAM || + ION_FLAG_CP_PIXEL || + ION_FLAG_CP_NON_PIXEL || + ION_FLAG_CP_CAMERA); +} + +int get_secure_vmid(unsigned long flags) +{ + if (flags & ION_FLAG_CP_TOUCH) + return VMID_CP_TOUCH; + if (flags & ION_FLAG_CP_BITSTREAM) + return VMID_CP_BITSTREAM; + if (flags & ION_FLAG_CP_PIXEL) + return VMID_CP_PIXEL; + if (flags & ION_FLAG_CP_NON_PIXEL) + return VMID_CP_NON_PIXEL; + if (flags & ION_FLAG_CP_CAMERA) + return VMID_CP_CAMERA; + + return -EINVAL; +} + +static void ion_system_secure_heap_free(struct ion_buffer *buffer) +{ + int ret; + u32 source_vm; + u32 dest_vm; + struct ion_heap *heap = buffer->heap; + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + source_vm = get_secure_vmid(buffer->flags); + dest_vm = VMID_HLOS; + + ret = msm_ion_hyp_assign_call(buffer->priv_virt, &source_vm, + sizeof(source_vm), &dest_vm, + sizeof(dest_vm)); + + if (ret) { + pr_err("%s: Not freeing memory since assign call failed\n", + __func__); + return; + } + buffer->heap = secure_heap->sys_heap; + secure_heap->sys_heap->ops->free(buffer); +} + +static int ion_system_secure_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, unsigned long align, + unsigned long flags) +{ + int ret; + u32 source_vm; + u32 dest_vm; + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + if (!ion_heap_is_system_secure_heap_type(secure_heap->heap.type) || + !is_cp_flag_present(flags)) { + pr_info("%s: Incorrect heap type or incorrect flags\n", + __func__); + return -EINVAL; + } + + source_vm = VMID_HLOS; + dest_vm = get_secure_vmid(flags); + if (dest_vm < 0) { + pr_info("%s: Unable to get secure VMID\n", __func__); + return -EINVAL; + } + + ret = secure_heap->sys_heap->ops->allocate(secure_heap->sys_heap, + buffer, size, align, flags); + if (ret) { + pr_info("%s: Failed to get allocation for %s, ret = %d\n", + __func__, heap->name, ret); + return ret; + } + ret = msm_ion_hyp_assign_call(buffer->priv_virt, &source_vm, + sizeof(source_vm), &dest_vm, + sizeof(dest_vm)); + + if (ret) + ion_system_secure_heap_free(buffer); + + return ret; +} + +static struct sg_table *ion_system_secure_heap_map_dma(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + return secure_heap->sys_heap->ops->map_dma(secure_heap->sys_heap, + buffer); +} + +static void ion_system_secure_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + secure_heap->sys_heap->ops->unmap_dma(secure_heap->sys_heap, + buffer); +} + +static void *ion_system_secure_heap_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + pr_info("%s: Kernel mapping from secure heap %s disallowed\n", + __func__, heap->name); + return ERR_PTR(-EINVAL); +} + +static void ion_system_secure_heap_unmap_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ +} + +static int ion_system_secure_heap_map_user(struct ion_heap *mapper, + struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + pr_info("%s: Mapping from secure heap %s disallowed\n", + __func__, mapper->name); + return -EINVAL; +} + +static int ion_system_secure_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, + int nr_to_scan) +{ + struct ion_system_secure_heap *secure_heap = container_of(heap, + struct ion_system_secure_heap, + heap); + + return secure_heap->sys_heap->ops->shrink(secure_heap->sys_heap, + gfp_mask, nr_to_scan); +} + +static struct ion_heap_ops system_secure_heap_ops = { + .allocate = ion_system_secure_heap_allocate, + .free = ion_system_secure_heap_free, + .map_dma = ion_system_secure_heap_map_dma, + .unmap_dma = ion_system_secure_heap_unmap_dma, + .map_kernel = ion_system_secure_heap_map_kernel, + .unmap_kernel = ion_system_secure_heap_unmap_kernel, + .map_user = ion_system_secure_heap_map_user, + .shrink = ion_system_secure_heap_shrink, +}; + +struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *unused) +{ + struct ion_system_secure_heap *heap; + + heap = kzalloc(sizeof(struct ion_system_secure_heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); + heap->heap.ops = &system_secure_heap_ops; + heap->heap.type = ION_HEAP_TYPE_SYSTEM_SECURE; + heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; + heap->sys_heap = get_ion_heap(ION_SYSTEM_HEAP_ID); + return &heap->heap; +} + +void ion_system_secure_heap_destroy(struct ion_heap *heap) +{ + kfree(heap); +} diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index e1ff23777c215709adf23d8ce54e24ca9a7da810..be9c5af4ea7dde3fe96ed2e617ef62ceac645a5d 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2014, 2018, The Linux Foundation. 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 and @@ -59,6 +59,10 @@ static struct ion_heap_desc ion_heap_meta[] = { .id = ION_SYSTEM_CONTIG_HEAP_ID, .name = ION_KMALLOC_HEAP_NAME, }, + { + .id = ION_SECURE_HEAP_ID, + .name = ION_SECURE_HEAP_NAME, + }, { .id = ION_CP_MM_HEAP_ID, .name = ION_MM_HEAP_NAME, @@ -277,7 +281,7 @@ int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, if (!ION_IS_CACHED(flags)) return 0; - if (flags & ION_FLAG_SECURE) + if ((flags & ION_FLAG_SECURE) || (get_secure_vmid(flags) > 0)) return 0; table = ion_sg_table(client, handle); @@ -366,6 +370,7 @@ static struct heap_types_info { MAKE_HEAP_TYPE_MAPPING(DMA), MAKE_HEAP_TYPE_MAPPING(SECURE_DMA), MAKE_HEAP_TYPE_MAPPING(REMOVED), + MAKE_HEAP_TYPE_MAPPING(SYSTEM_SECURE), }; static int msm_ion_get_heap_type_from_dt_node(struct device_node *node, @@ -644,6 +649,11 @@ out: return ret; } +int ion_heap_is_system_secure_heap_type(enum ion_heap_type type) +{ + return type == ((enum ion_heap_type) ION_HEAP_TYPE_SYSTEM_SECURE); +} + int ion_heap_allow_secure_allocation(enum ion_heap_type type) { return type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); @@ -722,11 +732,11 @@ long msm_ion_custom_ioctl(struct ion_client *client, down_read(&mm->mmap_sem); - start = (unsigned long) data.flush_data.vaddr; - end = (unsigned long) data.flush_data.vaddr - + data.flush_data.length; + start = (unsigned long)data.flush_data.vaddr + + data.flush_data.offset; + end = start + data.flush_data.length; - if (start && check_vaddr_bounds(start, end)) { + if (check_vaddr_bounds(start, end)) { pr_err("%s: virtual address %pK is out of bounds\n", __func__, data.flush_data.vaddr); ret = -EINVAL; @@ -921,7 +931,9 @@ static struct ion_heap *msm_ion_heap_create(struct ion_platform_heap *heap_data) case ION_HEAP_TYPE_REMOVED: heap = ion_removed_heap_create(heap_data); break; - + case ION_HEAP_TYPE_SYSTEM_SECURE: + heap = ion_system_secure_heap_create(heap_data); + break; default: heap = ion_heap_create(heap_data); } @@ -953,11 +965,29 @@ static void msm_ion_heap_destroy(struct ion_heap *heap) case ION_HEAP_TYPE_REMOVED: ion_removed_heap_destroy(heap); break; + case ION_HEAP_TYPE_SYSTEM_SECURE: + ion_system_secure_heap_destroy(heap); + break; default: ion_heap_destroy(heap); } } +struct ion_heap *get_ion_heap(int heap_id) +{ + int i; + struct ion_heap *heap; + + for (i = 0; i < num_heaps; i++) { + heap = heaps[i]; + if (heap->id == heap_id) + return heap; + } + + pr_err("%s: heap_id %d not found\n", __func__, heap_id); + return NULL; +} + static int msm_ion_probe(struct platform_device *pdev) { static struct ion_device *new_dev; diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index ac4840920351c0c4a9f6ce56642fa47db548b9f0..619e9cbe043c723f9f2eb95499dc0ed5647d1e0a 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -153,6 +153,9 @@ int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, int msm_ion_secure_table(struct sg_table *table); int msm_ion_unsecure_table(struct sg_table *table); +int msm_ion_hyp_assign_call(struct sg_table *table, + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size); #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -182,6 +185,12 @@ static inline int msm_ion_unsecure_table(struct sg_table *table) return -ENODEV; } +static inline int msm_ion_hyp_assign_call(struct sg_table *table, + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size) +{ + return -ENODEV; +} #endif /* CONFIG_ION */ diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index 39eb7a9446961b617d9874db62cb09aa97d2e488..c0523bea119211c0a41567be48faf4cac2cf5ba9 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google, Inc - * Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016, The Linux Foundation. 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 and @@ -37,6 +37,19 @@ struct cp2_lock_req { u32 lock; } __attribute__ ((__packed__)); + +struct mem_prot_info { + phys_addr_t addr; + u64 size; +}; + +struct info_list { + struct mem_prot_info *list_head; + u64 list_size; +}; + + +#define MEM_PROT_ASSIGN_ID 0x16 #define MEM_PROTECT_LOCK_ID2 0x0A #define MEM_PROTECT_LOCK_ID2_FLAT 0x11 #define V2_CHUNK_SIZE SZ_1M @@ -172,6 +185,74 @@ int msm_ion_unsecure_table(struct sg_table *table) } +static struct info_list *get_info_list(struct sg_table *table) +{ + int i; + struct scatterlist *sg; + struct mem_prot_info *info; + struct info_list *list; + + info = kmalloc_array(table->nents, (sizeof(struct mem_prot_info)), + GFP_KERNEL | __GFP_ZERO); + if (!info) + return NULL; + + for_each_sg(table->sgl, sg, table->nents, i) { + info[i].addr = page_to_phys(sg_page(sg)); + info[i].size = sg->length; + } + + list = kzalloc(sizeof(struct info_list), GFP_KERNEL); + if (!list) { + kfree(info); + return NULL; + } + + list->list_head = info; + list->list_size = table->nents * sizeof(struct mem_prot_info); + return list; +} + +static void destroy_info_list(struct info_list *info_list) +{ + kfree(info_list->list_head); + kfree(info_list); +} + +int msm_ion_hyp_assign_call(struct sg_table *table, + u32 *source_vm_list, u32 source_list_size, + u32 *dest_vm_list, u32 dest_list_size) +{ + struct info_list *info_list = NULL; + int ret; + struct scm_desc desc = {0}; + + info_list = get_info_list(table); + + if (!info_list) { + pr_info("%s: Failed to assign memory protection\n", __func__); + return -ENOMEM; + } + + desc.args[0] = virt_to_phys(info_list->list_head); + desc.args[1] = info_list->list_size; + desc.args[2] = virt_to_phys(source_vm_list); + desc.args[3] = source_list_size; + desc.args[4] = virt_to_phys(dest_vm_list); + desc.args[5] = dest_list_size; + desc.args[6] = 0; + desc.arginfo = SCM_ARGS(7, SCM_RO, SCM_VAL, SCM_RO, SCM_VAL, SCM_RO, + SCM_VAL, SCM_VAL); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + MEM_PROT_ASSIGN_ID), &desc); + if (ret) + pr_info("%s: Failed to assign memory protection, ret = %d\n", + __func__, ret); + destroy_info_list(info_list); + return ret; +} + #define MAKE_CP_VERSION(major, minor, patch) \ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF)) diff --git a/drivers/staging/android/ion/msm_ion_priv.h b/drivers/staging/android/ion/msm_ion_priv.h index cb9b35c29ed5a528c8fc46380cf3b96448c66cbc..9256758c46bd7bbabf7225f628aa54c99537d877 100644 --- a/drivers/staging/android/ion/msm_ion_priv.h +++ b/drivers/staging/android/ion/msm_ion_priv.h @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2018 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -49,6 +49,9 @@ void ion_iommu_heap_destroy(struct ion_heap *); struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *); void ion_cp_heap_destroy(struct ion_heap *); +struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *); +void ion_system_secure_heap_destroy(struct ion_heap *); + long msm_ion_custom_ioctl(struct ion_client *client, unsigned int cmd, unsigned long arg); @@ -106,12 +109,15 @@ void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base, void ion_mem_map_show(struct ion_heap *heap); +int ion_heap_is_system_secure_heap_type(enum ion_heap_type type); + int ion_heap_allow_secure_allocation(enum ion_heap_type type); int ion_heap_allow_heap_secure(enum ion_heap_type type); int ion_heap_allow_handle_secure(enum ion_heap_type type); +int get_secure_vmid(unsigned long flags); /** * ion_create_chunked_sg_table - helper function to create sg table * with specified chunk size diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index b15188623ef97bc27bea2164b91c68f26dea562f..c60d9060609f18aabd26ce7e7d015de33a7bc997 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -345,8 +345,21 @@ static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src) * the later of the two */ if (dst_pt->parent == src_pt->parent) { - if (dst_pt->parent->ops->compare(dst_pt, src_pt) - == -1) { + int cmp_val; + int (*cmp_fn) + (struct sync_pt *, struct sync_pt *); + + cmp_fn = dst_pt->parent->ops->compare; + cmp_val = cmp_fn(dst_pt, src_pt); + + /* + * Out-of-order users like oneshot don't follow + * a timeline ordering. + */ + if (cmp_val != -cmp_fn(src_pt, dst_pt)) + break; + + if (cmp_val == -1) { struct sync_pt *new_pt = sync_pt_dup(src_pt); if (new_pt == NULL) diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h index d1b0df383e0d692ae8b2f92eb22e2949e602c45a..9a39738a1705726ac40142fb2e1c9a1779ac16b7 100644 --- a/drivers/staging/android/uapi/msm_ion.h +++ b/drivers/staging/android/uapi/msm_ion.h @@ -6,6 +6,7 @@ enum msm_ion_heap_types { ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1, ION_HEAP_TYPE_SECURE_DMA = ION_HEAP_TYPE_MSM_START, + ION_HEAP_TYPE_SYSTEM_SECURE, ION_HEAP_TYPE_REMOVED, /* * if you add a heap type here you should also add it to @@ -130,8 +131,8 @@ enum cp_mem_usage { #define ION_MM_FIRMWARE_HEAP_NAME "mm_fw" #define ION_PIL1_HEAP_NAME "pil_1" #define ION_PIL2_HEAP_NAME "pil_2" -#define ION_SECURE_HEAP_NAME "secure_heap" #define ION_QSECOM_HEAP_NAME "qsecom" +#define ION_SECURE_HEAP_NAME "secure_heap" #define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED) #define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED) diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index bf1299847def770cb0375ed4d22add7bbd283708..ab25987676fcc3d44638c7f843436cff7bee371c 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -278,6 +278,7 @@ static long msm_thermal_process_voltage_table_req( voltage->voltage_table[idx] = voltage_table_ptr[cluster_id][table_idx]; } + voltage->voltage_table_len = idx; copy_and_return: ret = copy_to_user((void __user *)(*arg), query, diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index f67b80b4d67368b8a0b5ad1c38cadbb5514ee011..56bc4f236dcb27b6bb2647d4382ef61e8f492c22 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. 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 and @@ -62,6 +62,7 @@ #define MSM_TSENS_PRINT "log_tsens_temperature" #define CPU_BUF_SIZE 64 #define CPU_DEVICE "cpu%d" +#define HOTPLUG_RETRY_INTERVAL_MS 100 #define THERM_CREATE_DEBUGFS_DIR(_node, _name, _parent, _ret) \ do { \ @@ -81,7 +82,7 @@ } while (0) static struct msm_thermal_data msm_thermal_info; -static struct delayed_work check_temp_work; +static struct delayed_work check_temp_work, retry_hotplug_work; static bool core_control_enabled; static uint32_t cpus_offlined; static cpumask_var_t cpus_previously_online; @@ -132,7 +133,9 @@ static bool therm_reset_enabled; static bool online_core; static bool cluster_info_probed; static bool cluster_info_nodes_called; +static bool in_suspend, retry_in_progress; static int *tsens_id_map; +static int *zone_id_tsens_map; static DEFINE_MUTEX(vdd_rstr_mutex); static DEFINE_MUTEX(psm_mutex); static DEFINE_MUTEX(cx_mutex); @@ -415,7 +418,8 @@ static void cpus_previously_online_update(void) cpumask_or(cpus_previously_online, cpus_previously_online, cpu_online_mask); put_online_cpus(); - cpulist_scnprintf(buf, sizeof(buf), cpus_previously_online); + scnprintf(buf, sizeof(buf), "%*pbl", + cpumask_pr_args(cpus_previously_online)); pr_debug("%s\n", buf); } @@ -503,11 +507,15 @@ static int msm_thermal_suspend_callback( case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: msm_thermal_update_freq(false, true); + in_suspend = true; + retry_in_progress = false; + cancel_delayed_work_sync(&retry_hotplug_work); break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: msm_thermal_update_freq(false, false); + in_suspend = false; if (hotplug_task) complete(&hotplug_notify_complete); else @@ -1197,8 +1205,9 @@ static int __ref init_cluster_freq_table(void) if (!cpu_set) { cpumask_clear_cpu(_cpu, cpus_previously_online); - cpumask_scnprintf(buf, sizeof(buf), - cpus_previously_online); + scnprintf(buf, sizeof(buf), "%*pb", + cpumask_pr_args( + cpus_previously_online)); pr_debug("Reset prev online to %s\n", buf); } @@ -1969,13 +1978,67 @@ static int check_sensor_id(int sensor_id) return ret; } -static int create_sensor_id_map(void) +static int zone_id_to_tsen_id(int zone_id, int *tsens_id) { int i = 0; int ret = 0; - tsens_id_map = kzalloc(sizeof(int) * max_tsens_num, - GFP_KERNEL); + for (i = 0; i < max_tsens_num; i++) { + if (zone_id == zone_id_tsens_map[i]) { + *tsens_id = tsens_id_map[i]; + break; + } + } + if (i == max_tsens_num) { + pr_err("Invalid sensor zone id:%d\n", zone_id); + return -EINVAL; + } + + return ret; +} + +static int create_sensor_zone_id_map(void) +{ + int i = 0; + int zone_id = -1; + + zone_id_tsens_map = devm_kzalloc(&msm_thermal_info.pdev->dev, + sizeof(int) * max_tsens_num, GFP_KERNEL); + + if (!zone_id_tsens_map) { + pr_err("Cannot allocate memory for zone_id_tsens_map\n"); + return -ENOMEM; + } + + for (i = 0; i < max_tsens_num; i++) { + char tsens_name[TSENS_NAME_MAX] = ""; + + snprintf(tsens_name, TSENS_NAME_MAX, TSENS_NAME_FORMAT, + tsens_id_map[i]); + zone_id = sensor_get_id(tsens_name); + if (zone_id < 0) { + pr_err("Error getting zone id for %s. err:%d\n", + tsens_name, zone_id); + goto fail; + } else { + zone_id_tsens_map[i] = zone_id; + } + } + return 0; + +fail: + devm_kfree(&msm_thermal_info.pdev->dev, zone_id_tsens_map); + return zone_id; +} + +static int create_sensor_id_map(struct device *dev) +{ + int i = 0; + int ret = 0; + + tsens_id_map = devm_kzalloc(dev, + sizeof(int) * max_tsens_num, GFP_KERNEL); + if (!tsens_id_map) { pr_err("Cannot allocate memory for tsens_id_map\n"); return -ENOMEM; @@ -1998,7 +2061,7 @@ static int create_sensor_id_map(void) return ret; fail: - kfree(tsens_id_map); + devm_kfree(dev, tsens_id_map); return ret; } @@ -2314,23 +2377,36 @@ static void vdd_mx_notify(struct therm_threshold *trig_thresh) pr_err("Failed to remove vdd mx restriction\n"); } mutex_unlock(&vdd_mx_mutex); - sensor_mgr_set_threshold(trig_thresh->sensor_id, + + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } } -static void msm_thermal_bite(int tsens_id, long temp) +static void msm_thermal_bite(int zone_id, long temp) { struct scm_desc desc; + int tsens_id = 0; + int ret = 0; - pr_err("TSENS:%d reached temperature:%ld. System reset\n", - tsens_id, temp); + ret = zone_id_to_tsen_id(zone_id, &tsens_id); + if (ret < 0) { + pr_err("Zone:%d reached temperature:%ld. Err = %d System reset\n", + zone_id, temp, ret); + } else { + pr_err("Tsens:%d reached temperature:%ld. System reset\n", + tsens_id, temp); + } if (!is_scm_armv8()) { - scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0); + scm_call(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, + NULL, 0, NULL, 0); } else { desc.args[0] = 0; desc.arginfo = SCM_ARGS(1); - scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, - THERM_SECURE_BITE_CMD), &desc); + scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, + THERM_SECURE_BITE_CMD), &desc); } } @@ -2382,8 +2458,7 @@ static void therm_reset_notify(struct therm_threshold *thresh_data) if (ret) pr_err("Unable to read TSENS sensor:%d. err:%d\n", thresh_data->sensor_id, ret); - msm_thermal_bite(tsens_id_map[thresh_data->sensor_id], - temp); + msm_thermal_bite(thresh_data->sensor_id, temp); break; case THERMAL_TRIP_CONFIGURABLE_LOW: break; @@ -2395,6 +2470,17 @@ static void therm_reset_notify(struct therm_threshold *thresh_data) thresh_data->threshold); } +static void retry_hotplug(struct work_struct *work) +{ + mutex_lock(&core_control_mutex); + if (retry_in_progress) { + pr_debug("Retrying hotplug\n"); + retry_in_progress = false; + complete(&hotplug_notify_complete); + } + mutex_unlock(&core_control_mutex); +} + #ifdef CONFIG_SMP static void __ref do_core_control(long temp) { @@ -2463,6 +2549,7 @@ static int __ref update_offline_cores(int val) uint32_t cpu = 0; int ret = 0; uint32_t previous_cpus_offlined = 0; + bool pend_hotplug_req = false; if (!core_control_enabled) return 0; @@ -2476,11 +2563,16 @@ static int __ref update_offline_cores(int val) continue; trace_thermal_pre_core_offline(cpu); ret = cpu_down(cpu); - if (ret) - pr_err("Unable to offline CPU%d. err:%d\n", + if (ret) { + pr_err_ratelimited( + "Unable to offline CPU%d. err:%d\n", cpu, ret); - else + pend_hotplug_req = true; + } else { + struct device *cpu_device = get_cpu_device(cpu); + kobject_uevent(&cpu_device->kobj, KOBJ_OFFLINE); pr_debug("Offlined CPU%d\n", cpu); + } trace_thermal_post_core_offline(cpu, cpumask_test_cpu(cpu, cpu_online_mask)); } else if (online_core && (previous_cpus_offlined & BIT(cpu))) { @@ -2496,15 +2588,26 @@ static int __ref update_offline_cores(int val) pr_debug("Onlining CPU%d is vetoed\n", cpu); } else if (ret) { cpus_offlined |= BIT(cpu); - pr_err("Unable to online CPU%d. err:%d\n", + pend_hotplug_req = true; + pr_err_ratelimited( + "Unable to online CPU%d. err:%d\n", cpu, ret); } else { + struct device *cpu_device = get_cpu_device(cpu); + kobject_uevent(&cpu_device->kobj, KOBJ_ONLINE); pr_debug("Onlined CPU%d\n", cpu); } trace_thermal_post_core_online(cpu, cpumask_test_cpu(cpu, cpu_online_mask)); } } + + if (pend_hotplug_req && !in_suspend && !retry_in_progress) { + retry_in_progress = true; + schedule_delayed_work(&retry_hotplug_work, + msecs_to_jiffies(HOTPLUG_RETRY_INTERVAL_MS)); + } + return ret; } @@ -2858,6 +2961,9 @@ static int do_psm(void) int i = 0; int auto_cnt = 0; + if (!psm_enabled) + return ret; + mutex_lock(&psm_mutex); for (i = 0; i < max_tsens_num; i++) { ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp); @@ -2955,6 +3061,9 @@ static void check_temp(struct work_struct *work) long temp = 0; int ret = 0; + if (!msm_thermal_probed) + return; + do_therm_reset(); ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp); @@ -2983,8 +3092,9 @@ static void check_temp(struct work_struct *work) reschedule: if (polling_enabled) - schedule_delayed_work(&check_temp_work, - msecs_to_jiffies(msm_thermal_info.poll_ms)); + queue_delayed_work(system_power_efficient_wq, + &check_temp_work, + msecs_to_jiffies(msm_thermal_info.poll_ms)); } static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb, @@ -3050,12 +3160,18 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) return 0; switch (type) { case THERMAL_TRIP_CONFIGURABLE_HI: - if (!(cpu_node->offline)) + if (!(cpu_node->offline)) { + pr_info("%s reached HI temp threshold: %d\n", + cpu_node->sensor_type, temp); cpu_node->offline = 1; + } break; case THERMAL_TRIP_CONFIGURABLE_LOW: - if (cpu_node->offline) + if (cpu_node->offline) { + pr_info("%s reached LOW temp threshold: %d\n", + cpu_node->sensor_type, temp); cpu_node->offline = 0; + } break; default: break; @@ -3067,13 +3183,14 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) pr_err("Hotplug task is not initialized\n"); return 0; } + /* Adjust cpus offlined bit based on temperature reading. */ static int hotplug_init_cpu_offlined(void) { long temp = 0; uint32_t cpu = 0; - if (!hotplug_enabled) + if (!hotplug_enabled || !hotplug_task) return 0; mutex_lock(&core_control_mutex); @@ -3090,8 +3207,7 @@ static int hotplug_init_cpu_offlined(void) if (temp >= msm_thermal_info.hotplug_temp_degC) cpus[cpu].offline = 1; - else if (temp <= (msm_thermal_info.hotplug_temp_degC - - msm_thermal_info.hotplug_temp_hysteresis_degC)) + else cpus[cpu].offline = 0; } mutex_unlock(&core_control_mutex); @@ -3295,6 +3411,13 @@ static void freq_mitigation_init(void) goto init_freq_thread; for_each_possible_cpu(cpu) { + /* + * Hotplug may not be enabled, + * make sure core sensor id is initialized. + */ + cpus[cpu].sensor_id = + sensor_get_id((char *)cpus[cpu].sensor_type); + cpus[cpu].id_type = THERM_ZONE_ID; if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu))) continue; hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]; @@ -3320,6 +3443,8 @@ init_freq_thread: pr_err("Failed to create frequency mitigation thread. err:%ld\n", PTR_ERR(freq_mitigation_task)); return; + } else { + complete(&freq_mitigation_complete); } } @@ -3608,8 +3733,11 @@ static void cx_phase_ctrl_notify(struct therm_threshold *trig_thresh) cx_phase_unlock_exit: mutex_unlock(&cx_mutex); cx_phase_ctrl_exit: - sensor_mgr_set_threshold(trig_thresh->sensor_id, + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } return; } @@ -3737,8 +3865,11 @@ static void vdd_restriction_notify(struct therm_threshold *trig_thresh) unlock_and_exit: mutex_unlock(&vdd_rstr_mutex); set_and_exit: - sensor_mgr_set_threshold(trig_thresh->sensor_id, + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } return; } @@ -3786,8 +3917,11 @@ static void ocr_notify(struct therm_threshold *trig_thresh) unlock_and_exit: mutex_unlock(&ocr_mutex); set_and_exit: - sensor_mgr_set_threshold(trig_thresh->sensor_id, - trig_thresh->threshold); + if (trig_thresh->cur_state != trig_thresh->trip_triggered) { + sensor_mgr_set_threshold(trig_thresh->sensor_id, + trig_thresh->threshold); + trig_thresh->cur_state = trig_thresh->trip_triggered; + } return; } @@ -3975,6 +4109,7 @@ int sensor_mgr_init_threshold(struct device *dev, thresh_ptr[i].trip_triggered = -1; thresh_ptr[i].parent = thresh_inp; thresh_ptr[i].threshold[0].temp = high_temp; + thresh_ptr[i].cur_state = -1; thresh_ptr[i].threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; thresh_ptr[i].threshold[1].temp = low_temp; @@ -3993,6 +4128,7 @@ int sensor_mgr_init_threshold(struct device *dev, thresh_ptr->trip_triggered = -1; thresh_ptr->parent = thresh_inp; thresh_ptr->threshold[0].temp = high_temp; + thresh_ptr->cur_state = -1; thresh_ptr->threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; thresh_ptr->threshold[1].temp = low_temp; @@ -4169,6 +4305,7 @@ static void interrupt_mode_init(void) if (polling_enabled) { pr_info("Interrupt mode init\n"); polling_enabled = 0; + create_sensor_zone_id_map(); disable_msm_thermal(); hotplug_init(); freq_mitigation_init(); @@ -4236,7 +4373,7 @@ static ssize_t __ref store_cc_enabled(struct kobject *kobj, hotplug_init_cpu_offlined(); mutex_lock(&core_control_mutex); update_offline_cores(cpus_offlined); - if (hotplug_enabled) { + if (hotplug_enabled && hotplug_task) { for_each_possible_cpu(cpu) { if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) @@ -4462,15 +4599,12 @@ int msm_thermal_pre_init(struct device *dev) return ret; } - if (create_sensor_id_map()) { + if (create_sensor_id_map(dev)) { pr_err("Creating sensor id map failed\n"); ret = -EINVAL; goto pre_init_exit; } - if (!tsens_temp_at_panic) - msm_thermal_panic_notifier_init(dev); - if (!thresh) { thresh = kzalloc( sizeof(struct threshold_info) * MSM_LIST_MAX_NR, @@ -4600,6 +4734,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata) register_reboot_notifier(&msm_thermal_reboot_notifier); pm_notifier(msm_thermal_suspend_callback, 0); + INIT_DELAYED_WORK(&retry_hotplug_work, retry_hotplug); INIT_DELAYED_WORK(&check_temp_work, check_temp); schedule_delayed_work(&check_temp_work, 0); @@ -4607,6 +4742,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata) cpus_previously_online_update(); register_cpu_notifier(&msm_thermal_cpu_notifier); } + msm_thermal_panic_notifier_init(&pdata->pdev->dev); return ret; } diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index a520817fbc368ae1b070f15d37608d07fb0869e2..f483fc6c97290bd5cd7be1fedbb89a17060f24ce 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -249,6 +249,9 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, char *name; int ret; + if (strlen(page) < len) + return -EOVERFLOW; + name = kstrdup(page, GFP_KERNEL); if (!name) return -ENOMEM; diff --git a/drivers/video/msm/mdss/mdss_debug_xlog.c b/drivers/video/msm/mdss/mdss_debug_xlog.c index 3c31de41829241c4c7503340f9cf10852047c28f..008ba402d52b4d947f70af89bdd07366947e96a2 100644 --- a/drivers/video/msm/mdss/mdss_debug_xlog.c +++ b/drivers/video/msm/mdss/mdss_debug_xlog.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018, The Linux Foundation. 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 and @@ -546,6 +546,11 @@ static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff, if (__mdss_xlog_dump_calc_range()) { len = mdss_xlog_dump_entry(xlog_buf, MDSS_XLOG_BUF_MAX); + if (len < 0 || len > count) { + pr_err("len is more than the size of user buffer\n"); + return 0; + } + if (copy_to_user(buff, xlog_buf, len)) return -EFAULT; *ppos += len; diff --git a/drivers/video/msm/mdss/mdss_livedisplay.c b/drivers/video/msm/mdss/mdss_livedisplay.c index 9537471115e271c3c964752d493abb05fea80fcd..6fcc3149351dd65d779d949d96946bfbe32ddaea 100644 --- a/drivers/video/msm/mdss/mdss_livedisplay.c +++ b/drivers/video/msm/mdss/mdss_livedisplay.c @@ -179,6 +179,9 @@ static void mdss_livedisplay_worker(struct work_struct *work) if (mlc == NULL) return; + if (mlc->mfd == NULL) + return; + ctrl_pdata = get_ctrl(mlc->mfd); if (ctrl_pdata == NULL) return; diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c index 1019016a5828874f2db8db6f22b1d229d196abf3..136375cf0cf64473c51209ee2b3774829457fcca 100644 --- a/drivers/video/msm/mdss/mdss_mdp_rotator.c +++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2018, The Linux Foundation. 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 and @@ -43,6 +43,7 @@ struct mdss_mdp_rot_pipe { struct mdss_mdp_rot_session_mgr { struct list_head queue; struct mutex session_lock; + struct mutex req_lock; int session_id; int session_count; @@ -77,6 +78,7 @@ int mdss_mdp_rot_mgr_init(void) mutex_init(&rot_mgr->session_lock); mutex_init(&rot_mgr->pipe_lock); + mutex_init(&rot_mgr->req_lock); INIT_LIST_HEAD(&rot_mgr->queue); rot_mgr->rot_work_queue = create_workqueue("rot_commit_workq"); if (!rot_mgr->rot_work_queue) { @@ -1017,9 +1019,11 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd, u32 flgs; struct mdss_mdp_data src_buf; + mutex_lock(&rot_mgr->req_lock); rot = mdss_mdp_rot_mgr_get_session(req->id); if (!rot) { pr_err("invalid session id=%x\n", req->id); + mutex_unlock(&rot_mgr->req_lock); return -ENOENT; } @@ -1070,6 +1074,7 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd, dst_buf_fail: mutex_unlock(&rot->lock); + mutex_unlock(&rot_mgr->req_lock); mdss_iommu_ctrl(0); return ret; } @@ -1079,9 +1084,11 @@ int mdss_mdp_rotator_unset(int ndx) struct mdss_mdp_rotator_session *rot; int ret = 0; + mutex_lock(&rot_mgr->req_lock); rot = mdss_mdp_rot_mgr_get_session(ndx); if (rot) ret = mdss_mdp_rotator_release(rot); + mutex_unlock(&rot_mgr->req_lock); return ret; } diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c index d8878ff6a2ae0c13e6b80ef4bc5cba40df296878..b17c66ef6977304085b2b7bb92d6de8f225e8626 100644 --- a/drivers/video/msm/mdss/mdss_mdp_util.c +++ b/drivers/video/msm/mdss/mdss_mdp_util.c @@ -438,6 +438,8 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, if (ps == NULL) return -EINVAL; + memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); + if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT)) return -ERANGE; @@ -446,7 +448,6 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, return -EINVAL; bpp = fmt->bpp; - memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); if (bwc_mode) { u32 height, meta_size; diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index d384a8b77ee8a705fe9763de2257b3c43224b816..0306c321165c9020feeb594bd6ce33bcdea1d8be 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -352,9 +352,6 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd, invalidate_mapping_pages(&inode->i_data, 0, -1); } /* Convert flock to posix lock */ - fl->fl_owner = (fl_owner_t)filp; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; fl->fl_flags |= FL_POSIX; fl->fl_flags ^= FL_FLOCK; diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 2497bf306c70e4593d552f6e427bfaa81a7d7ccc..4baf1d2b39e410ffb501c2aba457fdceadcc2cdb 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -252,7 +252,8 @@ static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key) */ static int afs_do_setlk(struct file *file, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host); + struct inode *inode = file_inode(file); + struct afs_vnode *vnode = AFS_FS_I(inode); afs_lock_type_t type; struct key *key = file->private_data; int ret; @@ -273,7 +274,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl) type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; - lock_flocks(); + spin_lock(&inode->i_lock); /* make sure we've got a callback on this file and that our view of the * data version is up to date */ @@ -420,7 +421,7 @@ given_lock: afs_vnode_fetch_status(vnode, NULL, key); error: - unlock_flocks(); + spin_unlock(&inode->i_lock); _leave(" = %d", ret); return ret; @@ -554,10 +555,6 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl) return -ENOLCK; /* we're simulating flock() locks using posix locks on the server */ - fl->fl_owner = (fl_owner_t) file; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - if (fl->fl_type == F_UNLCK) return afs_do_unlk(file, fl); return afs_do_setlk(file, fl); diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 8ad277990eacc37236a57c9c3415853dc8806505..d096316533dac7f262d02f68fabd2faafb351be5 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -109,7 +109,7 @@ cont: spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); /* Already gone or negative dentry (under construction) - try next */ - if (q->d_count == 0 || !simple_positive(q)) { + if (!d_count(q) || !simple_positive(q)) { spin_unlock(&q->d_lock); next = q->d_child.next; goto cont; @@ -267,7 +267,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, else ino_count++; - if (p->d_count > ino_count) { + if (d_count(p) > ino_count) { top_ino->last_used = jiffies; dput(p); return 1; @@ -409,7 +409,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, if (!exp_leaves) { /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 1; - if (dentry->d_count > ino_count) + if (d_count(dentry) > ino_count) goto next; if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { @@ -423,7 +423,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, } else { /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 1; - if (dentry->d_count > ino_count) + if (d_count(dentry) > ino_count) goto next; expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 79ab4cb3590a4f690764b3f52e9a25771b8147d6..44e71b64db76422eb091f2815958baaf9b5baa1d 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -179,7 +179,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) spin_lock(&active->d_lock); /* Already gone? */ - if (active->d_count == 0) + if (!d_count(active)) goto next; qstr = &active->d_name; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 0cf23a7b88c2e302dd8d85522e0968b9c00f07f6..0d4c4bec4f6d0639e6ea45b269874f2f8a990fd4 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -903,8 +903,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, } else if (realdn) { dout("dn %p (%d) spliced with %p (%d) " "inode %p ino %llx.%llx\n", - dn, dn->d_count, - realdn, realdn->d_count, + dn, d_count(dn), + realdn, d_count(realdn), realdn->d_inode, ceph_vinop(realdn->d_inode)); dput(dn); dn = realdn; diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c index 669622fd1ae3d52af418cc4c283a5f22513bca73..513e2e0ae53d03bb7b18bcca74a2191476c580cb 100644 --- a/fs/ceph/ioctl.c +++ b/fs/ceph/ioctl.c @@ -111,6 +111,8 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg) return PTR_ERR(req); req->r_inode = inode; ihold(inode); + req->r_num_caps = 1; + req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL; req->r_args.setlayout.layout.fl_stripe_unit = @@ -157,6 +159,7 @@ static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg) return PTR_ERR(req); req->r_inode = inode; ihold(inode); + req->r_num_caps = 1; req->r_args.setlayout.layout.fl_stripe_unit = cpu_to_le32(l.stripe_unit); diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index ebbf680378e2ad3ad956babeb5b521e619830bcb..fbc39c47bacd17150581e2741531c610e5e89f56 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -2,11 +2,31 @@ #include #include +#include #include "super.h" #include "mds_client.h" #include +static u64 lock_secret; + +static inline u64 secure_addr(void *addr) +{ + u64 v = lock_secret ^ (u64)(unsigned long)addr; + /* + * Set the most significant bit, so that MDS knows the 'owner' + * is sufficient to identify the owner of lock. (old code uses + * both 'owner' and 'pid') + */ + v |= (1ULL << 63); + return v; +} + +void __init ceph_flock_init(void) +{ + get_random_bytes(&lock_secret, sizeof(lock_secret)); +} + /** * Implement fcntl and flock locking functions. */ @@ -14,17 +34,18 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, int cmd, u8 wait, struct file_lock *fl) { struct inode *inode = file_inode(file); - struct ceph_mds_client *mdsc = - ceph_sb_to_client(inode->i_sb)->mdsc; + struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_mds_request *req; int err; u64 length = 0; + u64 owner; req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); if (IS_ERR(req)) return PTR_ERR(req); req->r_inode = inode; ihold(inode); + req->r_num_caps = 1; /* mds requires start and length rather than start and end */ if (LLONG_MAX == fl->fl_end) @@ -32,25 +53,24 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, else length = fl->fl_end - fl->fl_start + 1; - dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " - "length: %llu, wait: %d, type: %d", (int)lock_type, - (int)operation, (u64)fl->fl_pid, fl->fl_start, - length, wait, fl->fl_type); + owner = secure_addr(fl->fl_owner); + + dout("ceph_lock_message: rule: %d, op: %d, owner: %llx, pid: %llu, " + "start: %llu, length: %llu, wait: %d, type: %d", (int)lock_type, + (int)operation, owner, (u64)fl->fl_pid, fl->fl_start, length, + wait, fl->fl_type); req->r_args.filelock_change.rule = lock_type; req->r_args.filelock_change.type = cmd; + req->r_args.filelock_change.owner = cpu_to_le64(owner); req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid); - /* This should be adjusted, but I'm not sure if - namespaces actually get id numbers*/ - req->r_args.filelock_change.pid_namespace = - cpu_to_le64((u64)(unsigned long)fl->fl_nspid); req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start); req->r_args.filelock_change.length = cpu_to_le64(length); req->r_args.filelock_change.wait = wait; err = ceph_mdsc_do_request(mdsc, inode, req); - if ( operation == CEPH_MDS_OP_GETFILELOCK){ + if (operation == CEPH_MDS_OP_GETFILELOCK) { fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid); if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type) fl->fl_type = F_RDLCK; @@ -87,14 +107,19 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) u8 wait = 0; u16 op = CEPH_MDS_OP_SETFILELOCK; - fl->fl_nspid = get_pid(task_tgid(current)); - dout("ceph_lock, fl_pid:%d", fl->fl_pid); + if (!(fl->fl_flags & FL_POSIX)) + return -ENOLCK; + /* No mandatory locks */ + if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK) + return -ENOLCK; + + dout("ceph_lock, fl_owner: %p", fl->fl_owner); /* set wait bit as appropriate, then make command as Ceph expects it*/ - if (F_SETLKW == cmd) - wait = 1; - if (F_GETLK == cmd) + if (IS_GETLK(cmd)) op = CEPH_MDS_OP_GETFILELOCK; + else if (IS_SETLKW(cmd)) + wait = 1; if (F_RDLCK == fl->fl_type) lock_cmd = CEPH_LOCK_SHARED; @@ -105,7 +130,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl); if (!err) { - if ( op != CEPH_MDS_OP_GETFILELOCK ){ + if (op != CEPH_MDS_OP_GETFILELOCK) { dout("mds locked, locking locally"); err = posix_lock_file(file, fl, NULL); if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { @@ -131,20 +156,22 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) { u8 lock_cmd; int err; - u8 wait = 1; - - fl->fl_nspid = get_pid(task_tgid(current)); - dout("ceph_flock, fl_pid:%d", fl->fl_pid); - - /* set wait bit, then clear it out of cmd*/ - if (cmd & LOCK_NB) - wait = 0; - cmd = cmd & (LOCK_SH | LOCK_EX | LOCK_UN); - /* set command sequence that Ceph wants to see: - shared lock, exclusive lock, or unlock */ - if (LOCK_SH == cmd) + u8 wait = 0; + + if (!(fl->fl_flags & FL_FLOCK)) + return -ENOLCK; + /* No mandatory locks */ + if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK) + return -ENOLCK; + + dout("ceph_flock, fl_file: %p", fl->fl_file); + + if (IS_SETLKW(cmd)) + wait = 1; + + if (F_RDLCK == fl->fl_type) lock_cmd = CEPH_LOCK_SHARED; - else if (LOCK_EX == cmd) + else if (F_WRLCK == fl->fl_type) lock_cmd = CEPH_LOCK_EXCL; else lock_cmd = CEPH_LOCK_UNLOCK; @@ -169,7 +196,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) } /** - * Must be called with BKL already held. Fills in the passed + * Must be called with lock_flocks() already held. Fills in the passed * counter variables, so you can prepare pagelist metadata before calling * ceph_encode_locks. */ @@ -192,7 +219,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) /** * Encode the flock and fcntl locks for the given inode into the ceph_filelock - * array. Must be called with lock_flocks() already held. + * array. Must be called with inode->i_lock already held. * If we encounter more of a specific lock type than expected, return -ENOSPC. */ int ceph_encode_locks_to_buffer(struct inode *inode, @@ -280,13 +307,11 @@ int lock_to_ceph_filelock(struct file_lock *lock, struct ceph_filelock *cephlock) { int err = 0; - cephlock->start = cpu_to_le64(lock->fl_start); cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1); cephlock->client = cpu_to_le64(0); - cephlock->pid = cpu_to_le64(lock->fl_pid); - cephlock->pid_namespace = - cpu_to_le64((u64)(unsigned long)lock->fl_nspid); + cephlock->pid = cpu_to_le64((u64)lock->fl_pid); + cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner)); switch (lock->fl_type) { case F_RDLCK: diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d6a5368864725eac41caa9e5ef21746536a2c9a1..a2a84ba0cbc4351c289ab825216247553f9b24a0 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1558,7 +1558,7 @@ retry: *base = ceph_ino(temp->d_inode); *plen = len; dout("build_path on %p %d built %llx '%.*s'\n", - dentry, dentry->d_count, *base, len, path); + dentry, d_count(dentry), *base, len, path); return path; } @@ -2488,20 +2488,20 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, struct ceph_filelock *flocks; encode_again: - lock_flocks(); + spin_lock(&inode->i_lock); ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks); - unlock_flocks(); + spin_unlock(&inode->i_lock); flocks = kmalloc((num_fcntl_locks+num_flock_locks) * sizeof(struct ceph_filelock), GFP_NOFS); if (!flocks) { err = -ENOMEM; goto out_free; } - lock_flocks(); + spin_lock(&inode->i_lock); err = ceph_encode_locks_to_buffer(inode, flocks, num_fcntl_locks, num_flock_locks); - unlock_flocks(); + spin_unlock(&inode->i_lock); if (err) { kfree(flocks); if (err == -ENOSPC) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 6627b26a800ca0e74649ecf439076bb9c6a4b095..151c1b1e6c0e6f8b2bf5dea24aea3cc7a1569fed 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -966,6 +966,7 @@ static int __init init_ceph(void) if (ret) goto out; + ceph_flock_init(); ceph_xattr_init(); ret = register_filesystem(&ceph_fs_type); if (ret) diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 7ccfdb4aea2e008e63f7ba00ab080c0fda2d0d09..2abe00ceca4a86dc07b5b70286f0585126288704 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -819,6 +819,7 @@ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg); extern const struct export_operations ceph_export_ops; /* locks.c */ +extern __init void ceph_flock_init(void); extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl); extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl); extern void ceph_count_locks(struct inode *inode, int *p_num, int *f_num); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f1f75826d27becca2e2f1a153be18a87040fa469..d375ce93080eecc9dc1e77569e137d9452746cb2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -773,7 +773,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) { - /* note that this is called by vfs setlease with lock_flocks held + /* note that this is called by vfs setlease with i_lock held to protect *lease from going away */ struct inode *inode = file_inode(file); struct cifsFileInfo *cfile = file->private_data; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f4a8577c3e91369e55f0dd7b3466faa5c78a773d..96cd9be00bf95f7fefa2cc4e1d30ed4e123ffaad 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -998,7 +998,7 @@ try_again: rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next); if (!rc) goto try_again; - locks_delete_block(flock); + posix_unblock_lock(flock); } return rc; } @@ -1091,6 +1091,7 @@ struct lock_to_push { static int cifs_push_posix_locks(struct cifsFileInfo *cfile) { + struct inode *inode = cfile->dentry->d_inode; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct file_lock *flock, **before; unsigned int count = 0, i = 0; @@ -1101,12 +1102,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) xid = get_xid(); - lock_flocks(); - cifs_for_each_lock(cfile->dentry->d_inode, before) { + spin_lock(&inode->i_lock); + cifs_for_each_lock(inode, before) { if ((*before)->fl_flags & FL_POSIX) count++; } - unlock_flocks(); + spin_unlock(&inode->i_lock); INIT_LIST_HEAD(&locks_to_send); @@ -1125,8 +1126,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) } el = locks_to_send.next; - lock_flocks(); - cifs_for_each_lock(cfile->dentry->d_inode, before) { + spin_lock(&inode->i_lock); + cifs_for_each_lock(inode, before) { flock = *before; if ((flock->fl_flags & FL_POSIX) == 0) continue; @@ -1151,7 +1152,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) lck->offset = flock->fl_start; el = el->next; } - unlock_flocks(); + spin_unlock(&inode->i_lock); list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { int stored_rc; diff --git a/fs/coda/dir.c b/fs/coda/dir.c index fc66861b359855d46b4fbdfae5a4fa1889906629..9fbea840cb0a577d578442e00b63929456a560b1 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -571,7 +571,7 @@ static int coda_dentry_revalidate(struct dentry *de, unsigned int flags) if (cii->c_flags & C_FLUSH) coda_flag_inode_children(inode, C_FLUSH); - if (de->d_count > 1) + if (d_count(de) > 1) /* pretend it's valid, but don't change the flags */ goto out; diff --git a/fs/compat.c b/fs/compat.c index 0095a6978eef16d82bcfe7549017614ed1a3b0b0..e121b3fb42d0150d3ca90b954fa94d81ef9dfd49 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -399,12 +399,28 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u } #endif +static unsigned int +convert_fcntl_cmd(unsigned int cmd) +{ + switch (cmd) { + case F_GETLK64: + return F_GETLK; + case F_SETLK64: + return F_SETLK; + case F_SETLKW64: + return F_SETLKW; + } + + return cmd; +} + asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs; struct flock f; long ret; + unsigned int conv_cmd; switch (cmd) { case F_GETLK: @@ -441,16 +457,18 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, case F_GETLK64: case F_SETLK64: case F_SETLKW64: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: ret = get_compat_flock64(&f, compat_ptr(arg)); if (ret != 0) break; old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK : - ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW), - (unsigned long)&f); + conv_cmd = convert_fcntl_cmd(cmd); + ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); set_fs(old_fs); - if (cmd == F_GETLK64 && ret == 0) { + if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { /* need to return lock information - see above for commentary */ if (f.l_start > COMPAT_LOFF_T_MAX) ret = -EOVERFLOW; @@ -471,8 +489,15 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) { - if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64)) + switch (cmd) { + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: return -EINVAL; + } return compat_sys_fcntl64(fd, cmd, arg); } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 148959e5b83fd4ed574045bdc3e2872137905aff..139e3d8bb1e27a8f7c5f8451c567aa1579d06a57 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -392,7 +392,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode); - BUG_ON(!lower_dentry->d_count); + BUG_ON(!d_count(lower_dentry)); ecryptfs_set_dentry_private(dentry, dentry_info); ecryptfs_set_dentry_lower(dentry, lower_dentry); diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index cc5079639b5f202f0f203e5a7390eee80f8c8946..591c36451dffc3b9c90a127ce8bbf7ebb8d3bb95 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1136,6 +1136,7 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, handle_t *handle; ext4_fsblk_t blk; int num, ret = 0, used_blks = 0; + unsigned long used_inos = 0; /* This should not happen, but just to be sure check this */ if (sb->s_flags & MS_RDONLY) { @@ -1166,22 +1167,37 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, * used inodes so we need to skip blocks with used inodes in * inode table. */ - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) - used_blks = DIV_ROUND_UP((EXT4_INODES_PER_GROUP(sb) - - ext4_itable_unused_count(sb, gdp)), - sbi->s_inodes_per_block); - - if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) || - ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) - - ext4_itable_unused_count(sb, gdp)) < - EXT4_FIRST_INO(sb)))) { - ext4_error(sb, "Something is wrong with group %u: " - "used itable blocks: %d; " - "itable unused count: %u", - group, used_blks, - ext4_itable_unused_count(sb, gdp)); - ret = 1; - goto err_out; + if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) { + used_inos = EXT4_INODES_PER_GROUP(sb) - + ext4_itable_unused_count(sb, gdp); + used_blks = DIV_ROUND_UP(used_inos, sbi->s_inodes_per_block); + + /* Bogus inode unused count? */ + if (used_blks < 0 || used_blks > sbi->s_itb_per_group) { + ext4_error(sb, "Something is wrong with group %u: " + "used itable blocks: %d; " + "itable unused count: %u", + group, used_blks, + ext4_itable_unused_count(sb, gdp)); + ret = 1; + goto err_out; + } + + used_inos += group * EXT4_INODES_PER_GROUP(sb); + /* + * Are there some uninitialized inodes in the inode table + * before the first normal inode? + */ + if ((used_blks != sbi->s_itb_per_group) && + (used_inos < EXT4_FIRST_INO(sb))) { + ext4_error(sb, "Something is wrong with group %u: " + "itable unused count: %u; " + "itables initialized count: %ld", + group, ext4_itable_unused_count(sb, gdp), + used_inos); + ret = 1; + goto err_out; + } } blk = ext4_inode_table(sb, gdp) + used_blks; diff --git a/fs/fcntl.c b/fs/fcntl.c index 0ec0ab37e8c3599dc89cf888d85bbdfb0dcc42cc..b788814086ef254d47937ac25688c73e1381f26f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -274,9 +274,19 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, case F_SETFL: err = setfl(fd, filp, arg); break; +#if BITS_PER_LONG != 32 + /* 32-bit arches must use fcntl64() */ + case F_OFD_GETLK: +#endif case F_GETLK: - err = fcntl_getlk(filp, (struct flock __user *) arg); + err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); break; +#if BITS_PER_LONG != 32 + /* 32-bit arches must use fcntl64() */ + case F_OFD_SETLK: + case F_OFD_SETLKW: +#endif + /* Fallthrough */ case F_SETLK: case F_SETLKW: err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); @@ -394,17 +404,20 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, goto out1; switch (cmd) { - case F_GETLK64: - err = fcntl_getlk64(f.file, (struct flock64 __user *) arg); - break; - case F_SETLK64: - case F_SETLKW64: - err = fcntl_setlk64(fd, f.file, cmd, - (struct flock64 __user *) arg); - break; - default: - err = do_fcntl(fd, cmd, arg, f.file); - break; + case F_GETLK64: + case F_OFD_GETLK: + err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); + break; + case F_SETLK64: + case F_SETLKW64: + case F_OFD_SETLK: + case F_OFD_SETLKW: + err = fcntl_setlk64(fd, f.file, cmd, + (struct flock64 __user *) arg); + break; + default: + err = do_fcntl(fd, cmd, arg, f.file); + break; } out1: fdput(f); diff --git a/fs/file.c b/fs/file.c index a885da15b6a353a21e38158b89b2795ab706ab4a..a07792c8f6c41a88eb6fd468208256d6fe1a1ccc 100644 --- a/fs/file.c +++ b/fs/file.c @@ -671,6 +671,37 @@ out_unlock: return -EBADF; } +/* + * variant of __close_fd that gets a ref on the file for later fput. + * The caller must ensure that filp_close() called on the file, and then + * an fput(). + */ +int __close_fd_get_file(unsigned int fd, struct file **res) +{ + struct files_struct *files = current->files; + struct file *file; + struct fdtable *fdt; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + if (fd >= fdt->max_fds) + goto out_unlock; + file = fdt->fd[fd]; + if (!file) + goto out_unlock; + rcu_assign_pointer(fdt->fd[fd], NULL); + __put_unused_fd(files, fd); + spin_unlock(&files->file_lock); + get_file(file); + *res = file; + return 0; + +out_unlock: + spin_unlock(&files->file_lock); + *res = NULL; + return -ENOENT; +} + void do_close_on_exec(struct files_struct *files) { unsigned i; diff --git a/fs/file_table.c b/fs/file_table.c index 28f02a7cbba189203bf9a77f454db0e8571292a2..ff3177707493d045e70b0fa67e5fe41da362f167 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -234,7 +234,7 @@ static void __fput(struct file *file) * in the file cleanup chain. */ eventpoll_release(file); - locks_remove_flock(file); + locks_remove_file(file); if (unlikely(file->f_flags & FASYNC)) { if (file->f_op && file->f_op->fasync) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ecead55e028fdd2ad0dc89844a4b0bdb0c4a6288..720b9edbf99ec83d6daa5ca25931ceb6a37ab281 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2051,7 +2051,6 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl) struct fuse_file *ff = file->private_data; /* emulate flock with POSIX locks */ - fl->fl_owner = (fl_owner_t) file; ff->flock = true; err = fuse_setlk(file, fl, 1); } diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index ad0dc38d87ab74dd7695a74b683a2baf7d3620d3..2398b410898faa2120ff1f665f77733913fc921b 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -896,7 +896,7 @@ out_uninit: * cluster; until we do, disable leases (by just returning -EINVAL), * unless the administrator has requested purely local locking. * - * Locking: called under lock_flocks + * Locking: called under i_lock * * Returns: errno */ diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index ffc4045fc62ef0b145ed830661f2bfb70922b9fd..c0978f0ffda577748421fbdbbaa4c0887d0e22bd 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -276,7 +276,7 @@ static int nlmsvc_unlink_block(struct nlm_block *block) dprintk("lockd: unlinking block %p...\n", block); /* Remove block from list */ - status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl); + status = posix_unblock_lock(&block->b_call->a_args.lock.fl); nlmsvc_remove_block(block); return status; } @@ -586,6 +586,7 @@ conf_lock: conflock->fl.fl_type = lock->fl.fl_type; conflock->fl.fl_start = lock->fl.fl_start; conflock->fl.fl_end = lock->fl.fl_end; + locks_release_private(&lock->fl); ret = nlm_lck_denied; out: if (block) @@ -744,8 +745,20 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; } +/* + * Since NLM uses two "keys" for tracking locks, we need to hash them down + * to one for the blocked_hash. Here, we're just xor'ing the host address + * with the pid in order to create a key value for picking a hash bucket. + */ +static unsigned long +nlmsvc_owner_key(struct file_lock *fl) +{ + return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid; +} + const struct lock_manager_operations nlmsvc_lock_operations = { .lm_compare_owner = nlmsvc_same_owner, + .lm_owner_key = nlmsvc_owner_key, .lm_notify = nlmsvc_notify_blocked, .lm_grant = nlmsvc_grant_deferred, }; diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 97e87415b145f7a6a0ed0e1a37c40a657209bf89..dc5c75930f0fea94145c9556f2aab6dbc8ea91a3 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -169,7 +169,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, again: file->f_locks = 0; - lock_flocks(); /* protects i_flock list */ + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl; fl = fl->fl_next) { if (fl->fl_lmops != &nlmsvc_lock_operations) continue; @@ -181,7 +181,7 @@ again: if (match(lockhost, host)) { struct file_lock lock = *fl; - unlock_flocks(); + spin_unlock(&inode->i_lock); lock.fl_type = F_UNLCK; lock.fl_start = 0; lock.fl_end = OFFSET_MAX; @@ -193,7 +193,7 @@ again: goto again; } } - unlock_flocks(); + spin_unlock(&inode->i_lock); return 0; } @@ -228,14 +228,14 @@ nlm_file_inuse(struct nlm_file *file) if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) return 1; - lock_flocks(); + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl; fl = fl->fl_next) { if (fl->fl_lmops == &nlmsvc_lock_operations) { - unlock_flocks(); + spin_unlock(&inode->i_lock); return 1; } } - unlock_flocks(); + spin_unlock(&inode->i_lock); file->f_locks = 0; return 0; } diff --git a/fs/locks.c b/fs/locks.c index f7b1de7e67358b8ae5006be68a4679d70e67aa8c..52eefa2cf066bdd4c3f4524224fc3a7235dbf90c 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -126,12 +126,19 @@ #include #include #include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include #include #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) -#define IS_LEASE(fl) (fl->fl_flags & FL_LEASE) +#define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG)) +#define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK) static bool lease_breaking(struct file_lock *fl) { @@ -153,30 +160,53 @@ int lease_break_time = 45; #define for_each_lock(inode, lockp) \ for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) -static LIST_HEAD(file_lock_list); -static LIST_HEAD(blocked_list); -static DEFINE_SPINLOCK(file_lock_lock); +/* + * The global file_lock_list is only used for displaying /proc/locks, so we + * keep a list on each CPU, with each list protected by its own spinlock via + * the file_lock_lglock. Note that alterations to the list also require that + * the relevant i_lock is held. + */ +DEFINE_STATIC_LGLOCK(file_lock_lglock); +static DEFINE_PER_CPU(struct hlist_head, file_lock_list); /* - * Protects the two list heads above, plus the inode->i_flock list + * The blocked_hash is used to find POSIX lock loops for deadlock detection. + * It is protected by blocked_lock_lock. + * + * We hash locks by lockowner in order to optimize searching for the lock a + * particular lockowner is waiting on. + * + * FIXME: make this value scale via some heuristic? We generally will want more + * buckets when we have more lockowners holding locks, but that's a little + * difficult to determine without knowing what the workload will look like. */ -void lock_flocks(void) -{ - spin_lock(&file_lock_lock); -} -EXPORT_SYMBOL_GPL(lock_flocks); +#define BLOCKED_HASH_BITS 7 +static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS); -void unlock_flocks(void) -{ - spin_unlock(&file_lock_lock); -} -EXPORT_SYMBOL_GPL(unlock_flocks); +/* + * This lock protects the blocked_hash. Generally, if you're accessing it, you + * want to be holding this lock. + * + * In addition, it also protects the fl->fl_block list, and the fl->fl_next + * pointer for file_lock structures that are acting as lock requests (in + * contrast to those that are acting as records of acquired locks). + * + * Note that when we acquire this lock in order to change the above fields, + * we often hold the i_lock as well. In certain cases, when reading the fields + * protected by this lock, we can skip acquiring it iff we already hold the + * i_lock. + * + * In particular, adding an entry to the fl_block list requires that you hold + * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting + * an entry from the list however only requires the file_lock_lock. + */ +static DEFINE_SPINLOCK(blocked_lock_lock); static struct kmem_cache *filelock_cache __read_mostly; static void locks_init_lock_heads(struct file_lock *fl) { - INIT_LIST_HEAD(&fl->fl_link); + INIT_HLIST_NODE(&fl->fl_link); INIT_LIST_HEAD(&fl->fl_block); init_waitqueue_head(&fl->fl_wait); } @@ -200,8 +230,12 @@ void locks_release_private(struct file_lock *fl) fl->fl_ops->fl_release_private(fl); fl->fl_ops = NULL; } - fl->fl_lmops = NULL; + if (fl->fl_lmops) { + if (fl->fl_lmops->lm_put_owner) + fl->fl_lmops->lm_put_owner(fl); + fl->fl_lmops = NULL; + } } EXPORT_SYMBOL_GPL(locks_release_private); @@ -210,13 +244,25 @@ void locks_free_lock(struct file_lock *fl) { BUG_ON(waitqueue_active(&fl->fl_wait)); BUG_ON(!list_empty(&fl->fl_block)); - BUG_ON(!list_empty(&fl->fl_link)); + BUG_ON(!hlist_unhashed(&fl->fl_link)); locks_release_private(fl); kmem_cache_free(filelock_cache, fl); } EXPORT_SYMBOL(locks_free_lock); +static void +locks_dispose_list(struct list_head *dispose) +{ + struct file_lock *fl; + + while (!list_empty(dispose)) { + fl = list_first_entry(dispose, struct file_lock, fl_block); + list_del_init(&fl->fl_block); + locks_free_lock(fl); + } +} + void locks_init_lock(struct file_lock *fl) { memset(fl, 0, sizeof(struct file_lock)); @@ -225,21 +271,10 @@ void locks_init_lock(struct file_lock *fl) EXPORT_SYMBOL(locks_init_lock); -static void locks_copy_private(struct file_lock *new, struct file_lock *fl) -{ - if (fl->fl_ops) { - if (fl->fl_ops->fl_copy_lock) - fl->fl_ops->fl_copy_lock(new, fl); - new->fl_ops = fl->fl_ops; - } - if (fl->fl_lmops) - new->fl_lmops = fl->fl_lmops; -} - /* * Initialize a new lock from an existing file_lock structure. */ -void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) +void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) { new->fl_owner = fl->fl_owner; new->fl_pid = fl->fl_pid; @@ -248,21 +283,30 @@ void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) new->fl_type = fl->fl_type; new->fl_start = fl->fl_start; new->fl_end = fl->fl_end; + new->fl_lmops = fl->fl_lmops; new->fl_ops = NULL; - new->fl_lmops = NULL; + + if (fl->fl_lmops) { + if (fl->fl_lmops->lm_get_owner) + fl->fl_lmops->lm_get_owner(new, fl); + } } -EXPORT_SYMBOL(__locks_copy_lock); +EXPORT_SYMBOL(locks_copy_conflock); void locks_copy_lock(struct file_lock *new, struct file_lock *fl) { - locks_release_private(new); + /* "new" must be a freshly-initialized lock */ + WARN_ON_ONCE(new->fl_ops); + + locks_copy_conflock(new, fl); - __locks_copy_lock(new, fl); new->fl_file = fl->fl_file; new->fl_ops = fl->fl_ops; - new->fl_lmops = fl->fl_lmops; - locks_copy_private(new, fl); + if (fl->fl_ops) { + if (fl->fl_ops->fl_copy_lock) + fl->fl_ops->fl_copy_lock(new, fl); + } } EXPORT_SYMBOL(locks_copy_lock); @@ -295,6 +339,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock, return -ENOMEM; fl->fl_file = filp; + fl->fl_owner = filp; fl->fl_pid = current->tgid; fl->fl_flags = FL_FLOCK; fl->fl_type = type; @@ -318,48 +363,43 @@ static int assign_type(struct file_lock *fl, long type) return 0; } -/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX - * style lock. - */ -static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, - struct flock *l) +static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock64 *l) { - off_t start, end; - switch (l->l_whence) { case SEEK_SET: - start = 0; + fl->fl_start = 0; break; case SEEK_CUR: - start = filp->f_pos; + fl->fl_start = filp->f_pos; break; case SEEK_END: - start = i_size_read(file_inode(filp)); + fl->fl_start = i_size_read(file_inode(filp)); break; default: return -EINVAL; } + if (l->l_start > OFFSET_MAX - fl->fl_start) + return -EOVERFLOW; + fl->fl_start += l->l_start; + if (fl->fl_start < 0) + return -EINVAL; /* POSIX-1996 leaves the case l->l_len < 0 undefined; POSIX-2001 defines it. */ - start += l->l_start; - if (start < 0) - return -EINVAL; - fl->fl_end = OFFSET_MAX; if (l->l_len > 0) { - end = start + l->l_len - 1; - fl->fl_end = end; + if (l->l_len - 1 > OFFSET_MAX - fl->fl_start) + return -EOVERFLOW; + fl->fl_end = fl->fl_start + l->l_len - 1; + } else if (l->l_len < 0) { - end = start - 1; - fl->fl_end = end; - start += l->l_len; - if (start < 0) + if (fl->fl_start + l->l_len < 0) return -EINVAL; - } - fl->fl_start = start; /* we record the absolute position */ - if (fl->fl_end < fl->fl_start) - return -EOVERFLOW; - + fl->fl_end = fl->fl_start - 1; + fl->fl_start += l->l_len; + } else + fl->fl_end = OFFSET_MAX; + fl->fl_owner = current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; @@ -370,52 +410,21 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, return assign_type(fl, l->l_type); } -#if BITS_PER_LONG == 32 -static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, - struct flock64 *l) +/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX + * style lock. + */ +static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock *l) { - loff_t start; - - switch (l->l_whence) { - case SEEK_SET: - start = 0; - break; - case SEEK_CUR: - start = filp->f_pos; - break; - case SEEK_END: - start = i_size_read(file_inode(filp)); - break; - default: - return -EINVAL; - } - - start += l->l_start; - if (start < 0) - return -EINVAL; - fl->fl_end = OFFSET_MAX; - if (l->l_len > 0) { - fl->fl_end = start + l->l_len - 1; - } else if (l->l_len < 0) { - fl->fl_end = start - 1; - start += l->l_len; - if (start < 0) - return -EINVAL; - } - fl->fl_start = start; /* we record the absolute position */ - if (fl->fl_end < fl->fl_start) - return -EOVERFLOW; - - fl->fl_owner = current->files; - fl->fl_pid = current->tgid; - fl->fl_file = filp; - fl->fl_flags = FL_POSIX; - fl->fl_ops = NULL; - fl->fl_lmops = NULL; + struct flock64 ll = { + .l_type = l->l_type, + .l_whence = l->l_whence, + .l_start = l->l_start, + .l_len = l->l_len, + }; - return assign_type(fl, l->l_type); + return flock64_to_posix_lock(filp, fl, &ll); } -#endif /* default lease lock manager operations */ static void lease_break_callback(struct file_lock *fl) @@ -484,47 +493,114 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) return fl1->fl_owner == fl2->fl_owner; } +/* Must be called with the i_lock held! */ +static void locks_insert_global_locks(struct file_lock *fl) +{ + lg_local_lock(&file_lock_lglock); + fl->fl_link_cpu = smp_processor_id(); + hlist_add_head(&fl->fl_link, this_cpu_ptr(&file_lock_list)); + lg_local_unlock(&file_lock_lglock); +} + +/* Must be called with the i_lock held! */ +static void locks_delete_global_locks(struct file_lock *fl) +{ + /* + * Avoid taking lock if already unhashed. This is safe since this check + * is done while holding the i_lock, and new insertions into the list + * also require that it be held. + */ + if (hlist_unhashed(&fl->fl_link)) + return; + lg_local_lock_cpu(&file_lock_lglock, fl->fl_link_cpu); + hlist_del_init(&fl->fl_link); + lg_local_unlock_cpu(&file_lock_lglock, fl->fl_link_cpu); +} + +static unsigned long +posix_owner_key(struct file_lock *fl) +{ + if (fl->fl_lmops && fl->fl_lmops->lm_owner_key) + return fl->fl_lmops->lm_owner_key(fl); + return (unsigned long)fl->fl_owner; +} + +static void locks_insert_global_blocked(struct file_lock *waiter) +{ + hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); +} + +static void locks_delete_global_blocked(struct file_lock *waiter) +{ + hash_del(&waiter->fl_link); +} + /* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. + * + * Must be called with blocked_lock_lock held. */ static void __locks_delete_block(struct file_lock *waiter) { + locks_delete_global_blocked(waiter); list_del_init(&waiter->fl_block); - list_del_init(&waiter->fl_link); waiter->fl_next = NULL; } -/* - */ -void locks_delete_block(struct file_lock *waiter) +static void locks_delete_block(struct file_lock *waiter) { - lock_flocks(); + spin_lock(&blocked_lock_lock); __locks_delete_block(waiter); - unlock_flocks(); + spin_unlock(&blocked_lock_lock); } -EXPORT_SYMBOL(locks_delete_block); /* Insert waiter into blocker's block list. * We use a circular list so that processes can be easily woken up in * the order they blocked. The documentation doesn't require this but * it seems like the reasonable thing to do. + * + * Must be called with both the i_lock and blocked_lock_lock held. The fl_block + * list itself is protected by the blocked_lock_lock, but by ensuring that the + * i_lock is also held on insertions we can avoid taking the blocked_lock_lock + * in some cases when we see that the fl_block list is empty. */ -static void locks_insert_block(struct file_lock *blocker, - struct file_lock *waiter) +static void __locks_insert_block(struct file_lock *blocker, + struct file_lock *waiter) { BUG_ON(!list_empty(&waiter->fl_block)); - list_add_tail(&waiter->fl_block, &blocker->fl_block); waiter->fl_next = blocker; - if (IS_POSIX(blocker)) - list_add(&waiter->fl_link, &blocked_list); + list_add_tail(&waiter->fl_block, &blocker->fl_block); + if (IS_POSIX(blocker) && !IS_OFDLCK(blocker)) + locks_insert_global_blocked(waiter); +} + +/* Must be called with i_lock held. */ +static void locks_insert_block(struct file_lock *blocker, + struct file_lock *waiter) +{ + spin_lock(&blocked_lock_lock); + __locks_insert_block(blocker, waiter); + spin_unlock(&blocked_lock_lock); } -/* Wake up processes blocked waiting for blocker. - * If told to wait then schedule the processes until the block list - * is empty, otherwise empty the block list ourselves. +/* + * Wake up processes blocked waiting for blocker. + * + * Must be called with the inode->i_lock held! */ static void locks_wake_up_blocks(struct file_lock *blocker) { + /* + * Avoid taking global lock if list is empty. This is safe since new + * blocked requests are only added to the list under the i_lock, and + * the i_lock is always held here. Note that removal from the fl_block + * list does not require the i_lock, so we must recheck list_empty() + * after acquiring the blocked_lock_lock. + */ + if (list_empty(&blocker->fl_block)) + return; + + spin_lock(&blocked_lock_lock); while (!list_empty(&blocker->fl_block)) { struct file_lock *waiter; @@ -536,35 +612,44 @@ static void locks_wake_up_blocks(struct file_lock *blocker) else wake_up(&waiter->fl_wait); } + spin_unlock(&blocked_lock_lock); } /* Insert file lock fl into an inode's lock list at the position indicated * by pos. At the same time add the lock to the global file lock list. + * + * Must be called with the i_lock held! */ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) { - list_add(&fl->fl_link, &file_lock_list); - fl->fl_nspid = get_pid(task_tgid(current)); /* insert into file's list */ fl->fl_next = *pos; *pos = fl; + + locks_insert_global_locks(fl); } -/* - * Delete a lock and then free it. - * Wake up processes that are blocked waiting for this lock, - * notify the FS that the lock has been cleared and - * finally free the lock. +/** + * locks_delete_lock - Delete a lock and then free it. + * @thisfl_p: pointer that points to the fl_next field of the previous + * inode->i_flock list entry + * + * Unlink a lock from all lists and free the namespace reference, but don't + * free it yet. Wake up processes that are blocked waiting for this lock and + * notify the FS that the lock has been cleared. + * + * Must be called with the i_lock held! */ -static void locks_delete_lock(struct file_lock **thisfl_p) +static void locks_unlink_lock(struct file_lock **thisfl_p) { struct file_lock *fl = *thisfl_p; + locks_delete_global_locks(fl); + *thisfl_p = fl->fl_next; fl->fl_next = NULL; - list_del_init(&fl->fl_link); if (fl->fl_nspid) { put_pid(fl->fl_nspid); @@ -572,7 +657,23 @@ static void locks_delete_lock(struct file_lock **thisfl_p) } locks_wake_up_blocks(fl); - locks_free_lock(fl); +} + +/* + * Unlink a lock from all lists and free it. + * + * Must be called with i_lock held! + */ +static void locks_delete_lock(struct file_lock **thisfl_p, + struct list_head *dispose) +{ + struct file_lock *fl = *thisfl_p; + + locks_unlink_lock(thisfl_p); + if (dispose) + list_add(&fl->fl_block, dispose); + else + locks_free_lock(fl); } /* Determine if lock sys_fl blocks lock caller_fl. Common functionality @@ -625,8 +726,9 @@ void posix_test_lock(struct file *filp, struct file_lock *fl) { struct file_lock *cfl; + struct inode *inode = file_inode(filp); - lock_flocks(); + spin_lock(&inode->i_lock); for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) { if (!IS_POSIX(cfl)) continue; @@ -634,12 +736,12 @@ posix_test_lock(struct file *filp, struct file_lock *fl) break; } if (cfl) { - __locks_copy_lock(fl, cfl); + locks_copy_conflock(fl, cfl); if (cfl->fl_nspid) fl->fl_pid = pid_vnr(cfl->fl_nspid); } else fl->fl_type = F_UNLCK; - unlock_flocks(); + spin_unlock(&inode->i_lock); return; } EXPORT_SYMBOL(posix_test_lock); @@ -665,8 +767,16 @@ EXPORT_SYMBOL(posix_test_lock); * Note: the above assumption may not be true when handling lock * requests from a broken NFS client. It may also fail in the presence * of tasks (such as posix threads) sharing the same open file table. - * * To handle those cases, we just bail out after a few iterations. + * + * For FL_OFDLCK locks, the owner is the filp, not the files_struct. + * Because the owner is not even nominally tied to a thread of + * execution, the deadlock detection below can't reasonably work well. Just + * skip it for those. + * + * In principle, we could do a more limited deadlock detection on FL_OFDLCK + * locks that just checks for the case where two tasks are attempting to + * upgrade from read to write locks on the same inode. */ #define MAX_DEADLK_ITERATIONS 10 @@ -676,18 +786,26 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) { struct file_lock *fl; - list_for_each_entry(fl, &blocked_list, fl_link) { + hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) { if (posix_same_owner(fl, block_fl)) return fl->fl_next; } return NULL; } +/* Must be called with the blocked_lock_lock held! */ static int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { int i = 0; + /* + * This deadlock detector can't reasonably detect deadlocks with + * FL_OFDLCK locks, since they aren't owned by a process, per-se. + */ + if (IS_OFDLCK(caller_fl)) + return 0; + while ((block_fl = what_owner_is_waiting_for(block_fl))) { if (i++ > MAX_DEADLK_ITERATIONS) return 0; @@ -711,6 +829,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) struct inode * inode = file_inode(filp); int error = 0; int found = 0; + LIST_HEAD(dispose); if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { new_fl = locks_alloc_lock(); @@ -718,7 +837,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) return -ENOMEM; } - lock_flocks(); + spin_lock(&inode->i_lock); if (request->fl_flags & FL_ACCESS) goto find_conflict; @@ -733,7 +852,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) if (request->fl_type == fl->fl_type) goto out; found = 1; - locks_delete_lock(before); + locks_delete_lock(before, &dispose); break; } @@ -748,9 +867,9 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) * give it the opportunity to lock the file. */ if (found) { - unlock_flocks(); + spin_unlock(&inode->i_lock); cond_resched(); - lock_flocks(); + spin_lock(&inode->i_lock); } find_conflict: @@ -777,9 +896,10 @@ find_conflict: error = 0; out: - unlock_flocks(); + spin_unlock(&inode->i_lock); if (new_fl) locks_free_lock(new_fl); + locks_dispose_list(&dispose); return error; } @@ -791,7 +911,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str struct file_lock *left = NULL; struct file_lock *right = NULL; struct file_lock **before; - int error, added = 0; + int error; + bool added = false; + LIST_HEAD(dispose); /* * We may need two file_lock structures for this operation, @@ -806,7 +928,12 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str new_fl2 = locks_alloc_lock(); } - lock_flocks(); + spin_lock(&inode->i_lock); + /* + * New lock request. Walk all POSIX locks and look for conflicts. If + * there are any, either return error or put the request on the + * blocker's list of waiters and the global blocked_hash. + */ if (request->fl_type != F_UNLCK) { for_each_lock(inode, before) { fl = *before; @@ -815,15 +942,21 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str if (!posix_locks_conflict(request, fl)) continue; if (conflock) - __locks_copy_lock(conflock, fl); + locks_copy_conflock(conflock, fl); error = -EAGAIN; if (!(request->fl_flags & FL_SLEEP)) goto out; + /* + * Deadlock detection and insertion into the blocked + * locks list must be done while holding the same lock! + */ error = -EDEADLK; - if (posix_locks_deadlock(request, fl)) - goto out; - error = FILE_LOCK_DEFERRED; - locks_insert_block(fl, request); + spin_lock(&blocked_lock_lock); + if (likely(!posix_locks_deadlock(request, fl))) { + error = FILE_LOCK_DEFERRED; + __locks_insert_block(fl, request); + } + spin_unlock(&blocked_lock_lock); goto out; } } @@ -845,7 +978,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str before = &fl->fl_next; } - /* Process locks with this owner. */ + /* Process locks with this owner. */ while ((fl = *before) && posix_same_owner(request, fl)) { /* Detect adjacent or overlapping regions (if same lock type) */ @@ -876,11 +1009,11 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str else request->fl_end = fl->fl_end; if (added) { - locks_delete_lock(before); + locks_delete_lock(before, &dispose); continue; } request = fl; - added = 1; + added = true; } else { /* Processing for different lock types is a bit @@ -891,7 +1024,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str if (fl->fl_start > request->fl_end) break; if (request->fl_type == F_UNLCK) - added = 1; + added = true; if (fl->fl_start < request->fl_start) left = fl; /* If the next lock in the list has a higher end @@ -906,22 +1039,25 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str * one (This may happen several times). */ if (added) { - locks_delete_lock(before); + locks_delete_lock(before, &dispose); continue; } - /* Replace the old lock with the new one. - * Wake up anybody waiting for the old one, - * as the change in lock type might satisfy - * their needs. + /* + * Replace the old lock with new_fl, and + * remove the old one. It's safe to do the + * insert here since we know that we won't be + * using new_fl later, and that the lock is + * just replacing an existing lock. */ - locks_wake_up_blocks(fl); - fl->fl_start = request->fl_start; - fl->fl_end = request->fl_end; - fl->fl_type = request->fl_type; - locks_release_private(fl); - locks_copy_private(fl, request); - request = fl; - added = 1; + error = -ENOLCK; + if (!new_fl) + goto out; + locks_copy_lock(new_fl, request); + request = new_fl; + new_fl = NULL; + locks_delete_lock(before, &dispose); + locks_insert_lock(before, request); + added = true; } } /* Go on to next lock. @@ -931,10 +1067,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str } /* - * The above code only modifies existing locks in case of - * merging or replacing. If new lock(s) need to be inserted - * all modifications are done bellow this, so it's safe yet to - * bail out. + * The above code only modifies existing locks in case of merging or + * replacing. If new lock(s) need to be inserted all modifications are + * done below this, so it's safe yet to bail out. */ error = -ENOLCK; /* "no luck" */ if (right && left == right && !new_fl2) @@ -974,7 +1109,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_wake_up_blocks(left); } out: - unlock_flocks(); + spin_unlock(&inode->i_lock); /* * Free any unused locks. */ @@ -982,6 +1117,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str locks_free_lock(new_fl); if (new_fl2) locks_free_lock(new_fl2); + locks_dispose_list(&dispose); return error; } @@ -1036,27 +1172,28 @@ EXPORT_SYMBOL(posix_lock_file_wait); /** * locks_mandatory_locked - Check for an active lock - * @inode: the file to check + * @file: the file to check * * Searches the inode's list of locks to find any POSIX locks which conflict. * This function is called from locks_verify_locked() only. */ -int locks_mandatory_locked(struct inode *inode) +int locks_mandatory_locked(struct file *file) { - fl_owner_t owner = current->files; + struct inode *inode = file_inode(file); struct file_lock *fl; /* * Search the lock list for this inode for any POSIX locks. */ - lock_flocks(); + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!IS_POSIX(fl)) continue; - if (fl->fl_owner != owner) + if (fl->fl_owner != current->files && + fl->fl_owner != file) break; } - unlock_flocks(); + spin_unlock(&inode->i_lock); return fl ? -EAGAIN : 0; } @@ -1079,19 +1216,30 @@ int locks_mandatory_area(int read_write, struct inode *inode, { struct file_lock fl; int error; + bool sleep = false; locks_init_lock(&fl); - fl.fl_owner = current->files; fl.fl_pid = current->tgid; fl.fl_file = filp; fl.fl_flags = FL_POSIX | FL_ACCESS; if (filp && !(filp->f_flags & O_NONBLOCK)) - fl.fl_flags |= FL_SLEEP; + sleep = true; fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; fl.fl_start = offset; fl.fl_end = offset + count - 1; for (;;) { + if (filp) { + fl.fl_owner = filp; + fl.fl_flags &= ~FL_SLEEP; + error = __posix_lock_file(inode, &fl, NULL); + if (!error) + break; + } + + if (sleep) + fl.fl_flags |= FL_SLEEP; + fl.fl_owner = current->files; error = __posix_lock_file(inode, &fl, NULL); if (error != FILE_LOCK_DEFERRED) break; @@ -1145,7 +1293,7 @@ int lease_modify(struct file_lock **before, int arg) printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); fl->fl_fasync = NULL; } - locks_delete_lock(before); + locks_delete_lock(before, NULL); } return 0; } @@ -1167,6 +1315,7 @@ static void time_out_leases(struct inode *inode) before = &inode->i_flock; while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { + trace_time_out_leases(inode, fl); if (past_time(fl->fl_downgrade_time)) lease_modify(before, F_RDLCK); if (past_time(fl->fl_break_time)) @@ -1176,30 +1325,42 @@ static void time_out_leases(struct inode *inode) } } +static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) +{ + if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) + return false; + return locks_conflict(breaker, lease); +} + /** * __break_lease - revoke all outstanding leases on file * @inode: the inode of the file to return - * @mode: the open mode (read or write) + * @mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR: + * break all leases + * @type: FL_LEASE: break leases and delegations; FL_DELEG: break + * only delegations * * break_lease (inlined for speed) has checked there already is at least * some kind of lock (maybe a lease) on this file. Leases are broken on * a call to open() or truncate(). This function can sleep unless you * specified %O_NONBLOCK to your open(). */ -int __break_lease(struct inode *inode, unsigned int mode) +int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) { int error = 0; struct file_lock *new_fl, *flock; struct file_lock *fl; unsigned long break_time; int i_have_this_lease = 0; + bool lease_conflict = false; int want_write = (mode & O_ACCMODE) != O_RDONLY; new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); if (IS_ERR(new_fl)) return PTR_ERR(new_fl); + new_fl->fl_flags = type; - lock_flocks(); + spin_lock(&inode->i_lock); time_out_leases(inode); @@ -1207,13 +1368,16 @@ int __break_lease(struct inode *inode, unsigned int mode) if ((flock == NULL) || !IS_LEASE(flock)) goto out; - if (!locks_conflict(flock, new_fl)) + for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { + if (leases_conflict(fl, new_fl)) { + lease_conflict = true; + if (fl->fl_owner == current->files) + i_have_this_lease = 1; + } + } + if (!lease_conflict) goto out; - for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) - if (fl->fl_owner == current->files) - i_have_this_lease = 1; - break_time = 0; if (lease_break_time > 0) { break_time = jiffies + lease_break_time * HZ; @@ -1222,6 +1386,8 @@ int __break_lease(struct inode *inode, unsigned int mode) } for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { + if (!leases_conflict(fl, new_fl)) + continue; if (want_write) { if (fl->fl_flags & FL_UNLOCK_PENDING) continue; @@ -1237,6 +1403,7 @@ int __break_lease(struct inode *inode, unsigned int mode) } if (i_have_this_lease || (mode & O_NONBLOCK)) { + trace_break_lease_noblock(inode, new_fl); error = -EWOULDBLOCK; goto out; } @@ -1248,11 +1415,13 @@ restart: if (break_time == 0) break_time++; locks_insert_block(flock, new_fl); - unlock_flocks(); + trace_break_lease_block(inode, new_fl); + spin_unlock(&inode->i_lock); error = wait_event_interruptible_timeout(new_fl->fl_wait, !new_fl->fl_next, break_time); - lock_flocks(); - __locks_delete_block(new_fl); + spin_lock(&inode->i_lock); + trace_break_lease_unblock(inode, new_fl); + locks_delete_block(new_fl); if (error >= 0) { if (error == 0) time_out_leases(inode); @@ -1262,14 +1431,14 @@ restart: */ for (flock = inode->i_flock; flock && IS_LEASE(flock); flock = flock->fl_next) { - if (locks_conflict(new_fl, flock)) + if (leases_conflict(new_fl, flock)) goto restart; } error = 0; } out: - unlock_flocks(); + spin_unlock(&inode->i_lock); locks_free_lock(new_fl); return error; } @@ -1322,9 +1491,10 @@ EXPORT_SYMBOL(lease_get_mtime); int fcntl_getlease(struct file *filp) { struct file_lock *fl; + struct inode *inode = file_inode(filp); int type = F_UNLCK; - lock_flocks(); + spin_lock(&inode->i_lock); time_out_leases(file_inode(filp)); for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) { @@ -1333,25 +1503,67 @@ int fcntl_getlease(struct file *filp) break; } } - unlock_flocks(); + spin_unlock(&inode->i_lock); return type; } -int generic_add_lease(struct file *filp, long arg, struct file_lock **flp) +/** + * check_conflicting_open - see if the given dentry points to a file that has + * an existing open that would conflict with the + * desired lease. + * @dentry: dentry to check + * @arg: type of lease that we're trying to acquire + * + * Check to see if there's an existing open fd on this file that would + * conflict with the lease we're trying to set. + */ +static int +check_conflicting_open(const struct dentry *dentry, const long arg) +{ + int ret = 0; + struct inode *inode = dentry->d_inode; + + if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) + return -EAGAIN; + + if ((arg == F_WRLCK) && ((d_count(dentry) > 1) || + (atomic_read(&inode->i_count) > 1))) + ret = -EAGAIN; + + return ret; +} + +static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp) { struct file_lock *fl, **before, **my_before = NULL, *lease; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; + bool is_deleg = (*flp)->fl_flags & FL_DELEG; int error; lease = *flp; + trace_generic_add_lease(inode, lease); - error = -EAGAIN; - if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) - goto out; - if ((arg == F_WRLCK) - && ((dentry->d_count > 1) - || (atomic_read(&inode->i_count) > 1))) + /* + * In the delegation case we need mutual exclusion with + * a number of operations that take the i_mutex. We trylock + * because delegations are an optional optimization, and if + * there's some chance of a conflict--we'd rather not + * bother, maybe that's a sign this just isn't a good file to + * hand out a delegation on. + */ + if (is_deleg && !mutex_trylock(&inode->i_mutex)) + return -EAGAIN; + + if (is_deleg && arg == F_WRLCK) { + /* Write delegations are not currently supported: */ + mutex_unlock(&inode->i_mutex); + WARN_ON_ONCE(1); + return -EINVAL; + } + + error = check_conflicting_open(dentry, arg); + if (error) goto out; /* @@ -1396,18 +1608,33 @@ int generic_add_lease(struct file *filp, long arg, struct file_lock **flp) goto out; locks_insert_lock(before, lease); - return 0; - + /* + * The check in break_lease() is lockless. It's possible for another + * open to race in after we did the earlier check for a conflicting + * open but before the lease was inserted. Check again for a + * conflicting open and cancel the lease if there is one. + * + * We also add a barrier here to ensure that the insertion of the lock + * precedes these checks. + */ + smp_mb(); + error = check_conflicting_open(dentry, arg); + if (error) + locks_unlink_lock(before); out: + if (is_deleg) + mutex_unlock(&inode->i_mutex); return error; } -int generic_delete_lease(struct file *filp, struct file_lock **flp) +static int generic_delete_lease(struct file *filp, struct file_lock **flp) { struct file_lock *fl, **before; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; + trace_generic_delete_lease(inode, *flp); + for (before = &inode->i_flock; ((fl = *before) != NULL) && IS_LEASE(fl); before = &fl->fl_next) { @@ -1427,7 +1654,7 @@ int generic_delete_lease(struct file *filp, struct file_lock **flp) * The (input) flp->fl_lmops->lm_break function is required * by break_lease(). * - * Called with file_lock_lock held. + * Called with inode->i_lock held. */ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) { @@ -1496,11 +1723,12 @@ static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) { + struct inode *inode = file_inode(filp); int error; - lock_flocks(); + spin_lock(&inode->i_lock); error = __vfs_setlease(filp, arg, lease); - unlock_flocks(); + spin_unlock(&inode->i_lock); return error; } @@ -1518,6 +1746,7 @@ static int do_fcntl_delete_lease(struct file *filp) static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) { struct file_lock *fl, *ret; + struct inode *inode = file_inode(filp); struct fasync_struct *new; int error; @@ -1531,15 +1760,12 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) return -ENOMEM; } ret = fl; - lock_flocks(); + spin_lock(&inode->i_lock); error = __vfs_setlease(filp, arg, &ret); - if (error) { - unlock_flocks(); - locks_free_lock(fl); - goto out_free_fasync; - } - if (ret != fl) - locks_free_lock(fl); + if (error) + goto out_unlock; + if (ret == fl) + fl = NULL; /* * fasync_insert_entry() returns the old entry if any. @@ -1551,9 +1777,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) new = NULL; error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); - unlock_flocks(); - -out_free_fasync: +out_unlock: + spin_unlock(&inode->i_lock); + if (fl) + locks_free_lock(fl); if (new) fasync_free(new); return error; @@ -1686,7 +1913,7 @@ EXPORT_SYMBOL_GPL(vfs_test_lock); static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) { - flock->l_pid = fl->fl_pid; + flock->l_pid = IS_OFDLCK(fl) ? -1 : fl->fl_pid; #if BITS_PER_LONG == 32 /* * Make sure we can represent the posix lock via @@ -1708,7 +1935,7 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) #if BITS_PER_LONG == 32 static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) { - flock->l_pid = fl->fl_pid; + flock->l_pid = IS_OFDLCK(fl) ? -1 : fl->fl_pid; flock->l_start = fl->fl_start; flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1; @@ -1720,7 +1947,7 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) /* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */ -int fcntl_getlk(struct file *filp, struct flock __user *l) +int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) { struct file_lock file_lock; struct flock flock; @@ -1737,6 +1964,16 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) if (error) goto out; + if (cmd == F_OFD_GETLK) { + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + + cmd = F_GETLK; + file_lock.fl_flags |= FL_OFDLCK; + file_lock.fl_owner = filp; + } + error = vfs_test_lock(filp, &file_lock); if (error) goto out; @@ -1745,11 +1982,13 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) if (file_lock.fl_type != F_UNLCK) { error = posix_lock_to_flock(&flock, &file_lock); if (error) - goto out; + goto rel_priv; } error = -EFAULT; if (!copy_to_user(l, &flock, sizeof(flock))) error = 0; +rel_priv: + locks_release_private(&file_lock); out: return error; } @@ -1820,6 +2059,22 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd, return error; } +/* Ensure that fl->fl_filp has compatible f_mode for F_SETLK calls */ +static int +check_fmode_for_setlk(struct file_lock *fl) +{ + switch (fl->fl_type) { + case F_RDLCK: + if (!(fl->fl_file->f_mode & FMODE_READ)) + return -EBADF; + break; + case F_WRLCK: + if (!(fl->fl_file->f_mode & FMODE_WRITE)) + return -EBADF; + } + return 0; +} + /* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ @@ -1855,25 +2110,36 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, error = flock_to_posix_lock(filp, file_lock, &flock); if (error) goto out; - if (cmd == F_SETLKW) { - file_lock->fl_flags |= FL_SLEEP; - } - - error = -EBADF; - switch (flock.l_type) { - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - goto out; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) + + error = check_fmode_for_setlk(file_lock); + if (error) + goto out; + + /* + * If the cmd is requesting file-private locks, then set the + * FL_OFDLCK flag and override the owner. + */ + switch (cmd) { + case F_OFD_SETLK: + error = -EINVAL; + if (flock.l_pid != 0) goto out; + + cmd = F_SETLK; + file_lock->fl_flags |= FL_OFDLCK; + file_lock->fl_owner = filp; break; - case F_UNLCK: - break; - default: + case F_OFD_SETLKW: error = -EINVAL; - goto out; + if (flock.l_pid != 0) + goto out; + + cmd = F_SETLKW; + file_lock->fl_flags |= FL_OFDLCK; + file_lock->fl_owner = filp; + /* Fallthrough */ + case F_SETLKW: + file_lock->fl_flags |= FL_SLEEP; } error = do_lock_file_wait(filp, cmd, file_lock); @@ -1907,7 +2173,7 @@ out: /* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */ -int fcntl_getlk64(struct file *filp, struct flock64 __user *l) +int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) { struct file_lock file_lock; struct flock64 flock; @@ -1924,6 +2190,16 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) if (error) goto out; + if (cmd == F_OFD_GETLK) { + error = -EINVAL; + if (flock.l_pid != 0) + goto out; + + cmd = F_GETLK64; + file_lock.fl_flags |= FL_OFDLCK; + file_lock.fl_owner = filp; + } + error = vfs_test_lock(filp, &file_lock); if (error) goto out; @@ -1935,7 +2211,8 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) error = -EFAULT; if (!copy_to_user(l, &flock, sizeof(flock))) error = 0; - + + locks_release_private(&file_lock); out: return error; } @@ -1975,25 +2252,36 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, error = flock64_to_posix_lock(filp, file_lock, &flock); if (error) goto out; - if (cmd == F_SETLKW64) { - file_lock->fl_flags |= FL_SLEEP; - } - - error = -EBADF; - switch (flock.l_type) { - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - goto out; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) + + error = check_fmode_for_setlk(file_lock); + if (error) + goto out; + + /* + * If the cmd is requesting file-private locks, then set the + * FL_OFDLCK flag and override the owner. + */ + switch (cmd) { + case F_OFD_SETLK: + error = -EINVAL; + if (flock.l_pid != 0) goto out; + + cmd = F_SETLK64; + file_lock->fl_flags |= FL_OFDLCK; + file_lock->fl_owner = filp; break; - case F_UNLCK: - break; - default: + case F_OFD_SETLKW: error = -EINVAL; - goto out; + if (flock.l_pid != 0) + goto out; + + cmd = F_SETLKW64; + file_lock->fl_flags |= FL_OFDLCK; + file_lock->fl_owner = filp; + /* Fallthrough */ + case F_SETLKW64: + file_lock->fl_flags |= FL_SLEEP; } error = do_lock_file_wait(filp, cmd, file_lock); @@ -2062,17 +2350,21 @@ EXPORT_SYMBOL(locks_remove_posix); /* * This function is called on the last close of an open file. */ -void locks_remove_flock(struct file *filp) +void locks_remove_file(struct file *filp) { struct inode * inode = file_inode(filp); struct file_lock *fl; struct file_lock **before; + LIST_HEAD(dispose); if (!inode->i_flock) return; + locks_remove_posix(filp, filp); + if (filp->f_op && filp->f_op->flock) { struct file_lock fl = { + .fl_owner = filp, .fl_pid = current->tgid, .fl_file = filp, .fl_flags = FL_FLOCK, @@ -2084,48 +2376,59 @@ void locks_remove_flock(struct file *filp) fl.fl_ops->fl_release_private(&fl); } - lock_flocks(); + spin_lock(&inode->i_lock); before = &inode->i_flock; while ((fl = *before) != NULL) { if (fl->fl_file == filp) { - if (IS_FLOCK(fl)) { - locks_delete_lock(before); - continue; - } if (IS_LEASE(fl)) { lease_modify(before, F_UNLCK); continue; } - /* What? */ - BUG(); + + /* + * There's a leftover lock on the list of a type that + * we didn't expect to see. Most likely a classic + * POSIX lock that ended up not getting released + * properly, or that raced onto the list somehow. Log + * some info about it and then just remove it from + * the list. + */ + WARN(!IS_FLOCK(fl), + "leftover lock: dev=%u:%u ino=%lu type=%hhd flags=0x%x start=%lld end=%lld\n", + MAJOR(inode->i_sb->s_dev), + MINOR(inode->i_sb->s_dev), inode->i_ino, + fl->fl_type, fl->fl_flags, + fl->fl_start, fl->fl_end); + + locks_delete_lock(before, &dispose); + continue; } before = &fl->fl_next; } - unlock_flocks(); + spin_unlock(&inode->i_lock); + locks_dispose_list(&dispose); } /** * posix_unblock_lock - stop waiting for a file lock - * @filp: how the file was opened * @waiter: the lock which was waiting * * lockd needs to block waiting for locks. */ int -posix_unblock_lock(struct file *filp, struct file_lock *waiter) +posix_unblock_lock(struct file_lock *waiter) { int status = 0; - lock_flocks(); + spin_lock(&blocked_lock_lock); if (waiter->fl_next) __locks_delete_block(waiter); else status = -ENOENT; - unlock_flocks(); + spin_unlock(&blocked_lock_lock); return status; } - EXPORT_SYMBOL(posix_unblock_lock); /** @@ -2148,6 +2451,11 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock); #include #include +struct locks_iterator { + int li_cpu; + loff_t li_pos; +}; + static void lock_get_status(struct seq_file *f, struct file_lock *fl, loff_t id, char *pfx) { @@ -2164,26 +2472,36 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, seq_printf(f, "%lld:%s ", id, pfx); if (IS_POSIX(fl)) { - seq_printf(f, "%6s %s ", - (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", + if (fl->fl_flags & FL_ACCESS) + seq_puts(f, "ACCESS"); + else if (IS_OFDLCK(fl)) + seq_puts(f, "OFDLCK"); + else + seq_puts(f, "POSIX "); + + seq_printf(f, " %s ", (inode == NULL) ? "*NOINODE*" : mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); } else if (IS_FLOCK(fl)) { if (fl->fl_type & LOCK_MAND) { - seq_printf(f, "FLOCK MSNFS "); + seq_puts(f, "FLOCK MSNFS "); } else { - seq_printf(f, "FLOCK ADVISORY "); + seq_puts(f, "FLOCK ADVISORY "); } } else if (IS_LEASE(fl)) { - seq_printf(f, "LEASE "); + if (fl->fl_flags & FL_DELEG) + seq_puts(f, "DELEG "); + else + seq_puts(f, "LEASE "); + if (lease_breaking(fl)) - seq_printf(f, "BREAKING "); + seq_puts(f, "BREAKING "); else if (fl->fl_file) - seq_printf(f, "ACTIVE "); + seq_puts(f, "ACTIVE "); else - seq_printf(f, "BREAKER "); + seq_puts(f, "BREAKER "); } else { - seq_printf(f, "UNKNOWN UNKNOWN "); + seq_puts(f, "UNKNOWN UNKNOWN "); } if (fl->fl_type & LOCK_MAND) { seq_printf(f, "%s ", @@ -2215,43 +2533,49 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, else seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end); } else { - seq_printf(f, "0 EOF\n"); + seq_puts(f, "0 EOF\n"); } } static int locks_show(struct seq_file *f, void *v) { + struct locks_iterator *iter = f->private; struct file_lock *fl, *bfl; - fl = list_entry(v, struct file_lock, fl_link); + fl = hlist_entry(v, struct file_lock, fl_link); - lock_get_status(f, fl, *((loff_t *)f->private), ""); + lock_get_status(f, fl, iter->li_pos, ""); list_for_each_entry(bfl, &fl->fl_block, fl_block) - lock_get_status(f, bfl, *((loff_t *)f->private), " ->"); + lock_get_status(f, bfl, iter->li_pos, " ->"); return 0; } static void *locks_start(struct seq_file *f, loff_t *pos) + __acquires(&blocked_lock_lock) { - loff_t *p = f->private; + struct locks_iterator *iter = f->private; - lock_flocks(); - *p = (*pos + 1); - return seq_list_start(&file_lock_list, *pos); + iter->li_pos = *pos + 1; + lg_global_lock(&file_lock_lglock); + spin_lock(&blocked_lock_lock); + return seq_hlist_start_percpu(&file_lock_list, &iter->li_cpu, *pos); } static void *locks_next(struct seq_file *f, void *v, loff_t *pos) { - loff_t *p = f->private; - ++*p; - return seq_list_next(v, &file_lock_list, pos); + struct locks_iterator *iter = f->private; + + ++iter->li_pos; + return seq_hlist_next_percpu(v, &file_lock_list, &iter->li_cpu, pos); } static void locks_stop(struct seq_file *f, void *v) + __releases(&blocked_lock_lock) { - unlock_flocks(); + spin_unlock(&blocked_lock_lock); + lg_global_unlock(&file_lock_lglock); } static const struct seq_operations locks_seq_operations = { @@ -2263,7 +2587,8 @@ static const struct seq_operations locks_seq_operations = { static int locks_open(struct inode *inode, struct file *filp) { - return seq_open_private(filp, &locks_seq_operations, sizeof(loff_t)); + return seq_open_private(filp, &locks_seq_operations, + sizeof(struct locks_iterator)); } static const struct file_operations proc_locks_operations = { @@ -2281,89 +2606,18 @@ static int __init proc_locks_init(void) module_init(proc_locks_init); #endif -/** - * lock_may_read - checks that the region is free of locks - * @inode: the inode that is being read - * @start: the first byte to read - * @len: the number of bytes to read - * - * Emulates Windows locking requirements. Whole-file - * mandatory locks (share modes) can prohibit a read and - * byte-range POSIX locks can prohibit a read if they overlap. - * - * N.B. this function is only ever called - * from knfsd and ownership of locks is never checked. - */ -int lock_may_read(struct inode *inode, loff_t start, unsigned long len) -{ - struct file_lock *fl; - int result = 1; - lock_flocks(); - for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { - if (IS_POSIX(fl)) { - if (fl->fl_type == F_RDLCK) - continue; - if ((fl->fl_end < start) || (fl->fl_start > (start + len))) - continue; - } else if (IS_FLOCK(fl)) { - if (!(fl->fl_type & LOCK_MAND)) - continue; - if (fl->fl_type & LOCK_READ) - continue; - } else - continue; - result = 0; - break; - } - unlock_flocks(); - return result; -} - -EXPORT_SYMBOL(lock_may_read); - -/** - * lock_may_write - checks that the region is free of locks - * @inode: the inode that is being written - * @start: the first byte to write - * @len: the number of bytes to write - * - * Emulates Windows locking requirements. Whole-file - * mandatory locks (share modes) can prohibit a write and - * byte-range POSIX locks can prohibit a write if they overlap. - * - * N.B. this function is only ever called - * from knfsd and ownership of locks is never checked. - */ -int lock_may_write(struct inode *inode, loff_t start, unsigned long len) -{ - struct file_lock *fl; - int result = 1; - lock_flocks(); - for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { - if (IS_POSIX(fl)) { - if ((fl->fl_end < start) || (fl->fl_start > (start + len))) - continue; - } else if (IS_FLOCK(fl)) { - if (!(fl->fl_type & LOCK_MAND)) - continue; - if (fl->fl_type & LOCK_WRITE) - continue; - } else - continue; - result = 0; - break; - } - unlock_flocks(); - return result; -} - -EXPORT_SYMBOL(lock_may_write); - static int __init filelock_init(void) { + int i; + filelock_cache = kmem_cache_create("file_lock_cache", sizeof(struct file_lock), 0, SLAB_PANIC, NULL); + lg_lock_init(&file_lock_lglock, "file_lock_lglock"); + + for_each_possible_cpu(i) + INIT_HLIST_HEAD(per_cpu_ptr(&file_lock_list, i)); + return 0; } diff --git a/fs/namei.c b/fs/namei.c index 58dd938bb5a900751a2ed025b604840ace2d02a2..e2af0479102ac3ff3833f8630c73cfb5c37c6f78 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2491,7 +2491,7 @@ static int handle_truncate(struct file *filp) /* * Refuse to truncate files with mandatory locks held on them. */ - error = locks_verify_locked(inode); + error = locks_verify_locked(filp); if (!error) error = security_path_truncate(path); if (!error) { diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ef0c394b7bf55cc5891e01fc4647acff2db41307..a445796715250f5ca28bef847d8b465925939d7c 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -73,20 +73,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ if (inode->i_flock == NULL) goto out; - /* Protect inode->i_flock using the file locks lock */ - lock_flocks(); + /* Protect inode->i_flock using the i_lock */ + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) continue; if (nfs_file_open_context(fl->fl_file) != ctx) continue; - unlock_flocks(); + spin_unlock(&inode->i_lock); status = nfs4_lock_delegation_recall(fl, state, stateid); if (status < 0) goto out; - lock_flocks(); + spin_lock(&inode->i_lock); } - unlock_flocks(); + spin_unlock(&inode->i_lock); out: return status; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f47f6a338a355e4ded7812114d449f525eb0f33b..5e0aab71586483333bb555f6e6b1386a7c0408ef 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1722,7 +1722,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) dir->i_ino, dentry->d_name.name); spin_lock(&dentry->d_lock); - if (dentry->d_count > 1) { + if (d_count(dentry) > 1) { spin_unlock(&dentry->d_lock); /* Start asynchronous writeout of the inode */ write_inode_now(dentry->d_inode, 0); @@ -1871,7 +1871,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name, - new_dentry->d_count); + d_count(new_dentry)); /* * For non-directories, check whether the target is busy and if so, @@ -1889,7 +1889,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, rehash = new_dentry; } - if (new_dentry->d_count > 2) { + if (d_count(new_dentry) > 2) { int err; /* copy the target dentry's name */ diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f8bd4ea2a8918339750232992ada681e9cf14408..d90d1d1d9188ab0483924ea169c2c60c839d95af 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -894,10 +894,6 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) is_local = 1; /* We're simulating flock() locks using posix locks on the server */ - fl->fl_owner = (fl_owner_t)filp; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl, is_local); return do_setlk(filp, cmd, fl, is_local); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8a67b3e633a56cb2f44f2691d58ebf30366fa353..a3fb2776f9bc9fef9a215db301fbb4a41ef03ea5 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1372,13 +1372,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ /* Guard against delegation returns and new lock/unlock calls */ down_write(&nfsi->rwsem); /* Protect inode->i_flock using the BKL */ - lock_flocks(); + spin_lock(&inode->i_lock); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) continue; if (nfs_file_open_context(fl->fl_file)->state != state) continue; - unlock_flocks(); + spin_unlock(&inode->i_lock); status = ops->recover_lock(state, fl); switch (status) { case 0: @@ -1405,9 +1405,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ /* kill_proc(fl->fl_pid, SIGLOST, 1); */ status = 0; } - lock_flocks(); + spin_lock(&inode->i_lock); } - unlock_flocks(); + spin_unlock(&inode->i_lock); out: up_write(&nfsi->rwsem); return status; diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 1f1f38f0c5d58703ca66c8477d551b708d9cab7b..60395ad3a2e475076ee3382e05b221aacdcaa60b 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -479,7 +479,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", dentry->d_parent->d_name.name, dentry->d_name.name, - dentry->d_count); + d_count(dentry)); nfs_inc_stats(dir, NFSIOS_SILLYRENAME); /* diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b0878e1921bed90fab99b81cf77ec1ac038510a8..4bd29c34a90cbf07add20a800ce1b5207529355c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2642,13 +2642,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); - /* only place dl_time is set. protected by lock_flocks*/ + /* Only place dl_time is set; protected by i_lock: */ dp->dl_time = get_seconds(); nfsd4_cb_recall(dp); } -/* Called from break_lease() with lock_flocks() held. */ +/* Called from break_lease() with i_lock held. */ static void nfsd_break_deleg_cb(struct file_lock *fl) { struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; @@ -2929,7 +2929,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f return NULL; locks_init_lock(fl); fl->fl_lmops = &nfsd_lease_mng_ops; - fl->fl_flags = FL_LEASE; + fl->fl_flags = FL_DELEG; fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; fl->fl_end = OFFSET_MAX; fl->fl_owner = (fl_owner_t)(dp->dl_file); @@ -4541,7 +4541,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) struct inode *inode = filp->fi_inode; int status = 0; - lock_flocks(); + spin_lock(&inode->i_lock); for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { if ((*flpp)->fl_owner == (fl_owner_t)lowner) { status = 1; @@ -4549,7 +4549,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) } } out: - unlock_flocks(); + spin_unlock(&inode->i_lock); return status; } diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 4b0a8d4a834501bf7cfba69e1ce4d5438807cbe4..d474f283d143be429abe09765bfb955ca597234b 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -973,7 +973,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, static int nilfs_tree_was_touched(struct dentry *root_dentry) { - return root_dentry->d_count > 1; + return d_count(root_dentry) > 1; } /** diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 159c97dfca563b75998ceb8fd791f1c916783bbb..fbc274fa8617a8f74ae6bb4616581c8876df0231 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -181,9 +181,10 @@ static void sdcardfs_canonical_path(const struct path *path, sdcardfs_get_real_lower(path->dentry, actual_path); } -static int sdcardfs_d_delete(const struct dentry * dentry) +/* 1 = delete, 0 = cache */ +static int sdcardfs_d_delete(const struct dentry *d) { - return dentry->d_inode && !S_ISDIR(dentry->d_inode->i_mode); + return SDCARDFS_SB(d->d_sb)->options.nocache ? 1 : 0; } const struct dentry_operations sdcardfs_ci_dops = { diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 6c8ffaab73526f32628d80d2571405d62198e15d..4502c3f602546b33dffa6444c6679248b21d8071 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -76,8 +76,10 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf, if (err >= 0) { if (sizeof(loff_t) > sizeof(long)) mutex_lock(&inode->i_mutex); - fsstack_copy_inode_size(inode, file_inode(lower_file)); - fsstack_copy_attr_times(inode, file_inode(lower_file)); + fsstack_copy_inode_size(inode, + lower_file->f_path.dentry->d_inode); + fsstack_copy_attr_times(inode, + lower_file->f_path.dentry->d_inode); if (sizeof(loff_t) > sizeof(long)) mutex_unlock(&inode->i_mutex); } @@ -295,8 +297,10 @@ static int sdcardfs_flush(struct file *file, fl_owner_t id) struct file *lower_file = NULL; lower_file = sdcardfs_lower_file(file); - if (lower_file && lower_file->f_op && lower_file->f_op->flush) + if (lower_file && lower_file->f_op && lower_file->f_op->flush) { + filemap_write_and_wait(file->f_mapping); err = lower_file->f_op->flush(lower_file, id); + } return err; } diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index b6f2c877a349e6b3a961c5cfa5b351fb4ece7500..16d3426805aa9d8c69d6419b55fd446add21f869 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -34,6 +34,7 @@ enum { Opt_reserved_mb, Opt_gid_derivation, Opt_default_normal, + Opt_nocache, Opt_unshared_obb, Opt_err, }; @@ -50,6 +51,7 @@ static const match_table_t sdcardfs_tokens = { {Opt_default_normal, "default_normal"}, {Opt_unshared_obb, "unshared_obb"}, {Opt_reserved_mb, "reserved_mb=%u"}, + {Opt_nocache, "nocache"}, {Opt_err, NULL} }; @@ -73,6 +75,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, /* by default, gid derivation is off */ opts->gid_derivation = false; opts->default_normal = false; + opts->nocache = false; *debug = 0; @@ -130,6 +133,9 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_default_normal: opts->default_normal = true; break; + case Opt_nocache: + opts->nocache = true; + break; case Opt_unshared_obb: opts->unshared_obb = true; break; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index f96405d7c317eb68c0f68d8ac300bbd85d5ff4a2..ea566e1c84d5872704425b974af17a00e29de868 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -198,6 +198,7 @@ struct sdcardfs_mount_options { bool default_normal; bool unshared_obb; unsigned int reserved_mb; + bool nocache; }; struct sdcardfs_vfsmount_options { diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index cffcdb11cb8ac8516e246524216f634bffe1e903..bd2eb0257020e6a6cf655a738dd183d4a896bf79 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -311,6 +311,10 @@ static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, seq_puts(m, ",default_normal"); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); + if (opts->nocache) + seq_printf(m, ",nocache"); + if (opts->unshared_obb) + seq_printf(m, ",unshared_obb"); return 0; }; diff --git a/fs/sdfat/Kconfig b/fs/sdfat/Kconfig index 683f1213ef7f9f38755429f8ecbb5f8cb96410d0..a5f4d669b09fa2c8be8a48e66a23cd489c08ed24 100644 --- a/fs/sdfat/Kconfig +++ b/fs/sdfat/Kconfig @@ -69,15 +69,18 @@ config SDFAT_CHECK_RO_ATTR config SDFAT_ALIGNED_MPAGE_WRITE bool "Enable supporting aligned mpage_write" - default y + default y if SDFAT_FS=y + default n if SDFAT_FS=m depends on SDFAT_FS config SDFAT_VIRTUAL_XATTR bool "Virtual xattr support for sdFAT" - default y + default n depends on SDFAT_FS help - To support virtual xattr. + If you enable this feature, it supports virtual xattr. + This feature will be deprecated because it might be the same with + "context" mount option. config SDFAT_VIRTUAL_XATTR_SELINUX_LABEL string "Default string for SELinux label" diff --git a/fs/sdfat/amap_smart.c b/fs/sdfat/amap_smart.c index 5a76bd96bd444427fae6c062f31e6206834e5378..46c35894a5f230c6c4fb069191af50098ff0d14d 100644 --- a/fs/sdfat/amap_smart.c +++ b/fs/sdfat/amap_smart.c @@ -705,7 +705,8 @@ static inline AU_INFO_T *amap_get_packing_au(AMAP_T *amap, int dest, int num_to_ } } - if ((PACKING_HARDLIMIT) && amap->n_need_packing >= PACKING_HARDLIMIT) { + if ((PACKING_HARDLIMIT != 0) && + amap->n_need_packing >= PACKING_HARDLIMIT) { /* Compulsory SLC flushing: * If there was no chance to do best-fit packing * and the # of AU-aligned allocation exceeds HARD threshold, diff --git a/fs/sdfat/blkdev.c b/fs/sdfat/blkdev.c index 264c670df0f0d957396f823708c5cb79922b4457..7a275ac19e1f2880e4a888ecad329c11e198bd90 100644 --- a/fs/sdfat/blkdev.c +++ b/fs/sdfat/blkdev.c @@ -96,7 +96,6 @@ s32 bdev_check_bdi_valid(struct super_block *sb) fsi->prev_eio |= SDFAT_EIO_BDI; sdfat_log_msg(sb, KERN_ERR, "%s: block device is " "eliminated.(bdi:%p)", __func__, sb->s_bdi); - sdfat_debug_warn_on(1); } return -ENXIO; } @@ -104,18 +103,13 @@ s32 bdev_check_bdi_valid(struct super_block *sb) return 0; } - -/* Make a readahead request */ -s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) +#if IS_BUILTIN(CONFIG_SDFAT_FS) +static void __bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) { - FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); u32 sects_per_page = (PAGE_SIZE >> sb->s_blocksize_bits); struct blk_plug plug; u64 i; - if (!fsi->bd_opened) - return -EIO; - blk_start_plug(&plug); for (i = 0; i < num_secs; i++) { if (i && !(i & (sects_per_page - 1))) @@ -123,6 +117,26 @@ s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) sb_breadahead(sb, (sector_t)(secno + i)); } blk_finish_plug(&plug); +} +#else +static void __bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) +{ + u64 i; + + for (i = 0; i < num_secs; i++) + sb_breadahead(sb, (sector_t)(secno + i)); +} +#endif + +/* Make a readahead request */ +s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) +{ + FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + + if (!fsi->bd_opened) + return -EIO; + + __bdev_readahead(sb, secno, num_secs); return 0; } @@ -159,7 +173,9 @@ s32 bdev_mread(struct super_block *sb, u64 secno, struct buffer_head **bh, u64 n if (!(fsi->prev_eio & SDFAT_EIO_READ)) { fsi->prev_eio |= SDFAT_EIO_READ; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); +#ifdef CONFIG_SDFAT_DEBUG sdfat_debug_warn_on(1); +#endif } return -EIO; @@ -213,7 +229,9 @@ no_bh: if (!(fsi->prev_eio & SDFAT_EIO_WRITE)) { fsi->prev_eio |= SDFAT_EIO_WRITE; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); +#ifdef CONFIG_SDFAT_DEBUG sdfat_debug_warn_on(1); +#endif } return -EIO; diff --git a/fs/sdfat/core.c b/fs/sdfat/core.c index 5a1e0e41591abe4dc0591ed50a3922ff08018c9f..a1f7feeffcb8548e98b3c5d3336599278a2a230d 100644 --- a/fs/sdfat/core.c +++ b/fs/sdfat/core.c @@ -158,7 +158,7 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s /* skip updating volume dirty flag, * if this volume has been mounted with read-only */ - if (sb->s_flags & MS_RDONLY) + if (sb_rdonly(sb)) return 0; if (!fsi->pbr_bh) { @@ -177,7 +177,8 @@ static s32 __fs_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_s bpb->bsx.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00; } else { /* FAT16/12 */ pbr16_t *bpb = (pbr16_t *) fsi->pbr_bh->b_data; - bpb->bpb.state = new_flag & VOL_DIRTY ? FAT_VOL_DIRTY : 0x00; + bpb->bpb.f16.state = new_flag & VOL_DIRTY ? + FAT_VOL_DIRTY : 0x00; } if (always_sync) @@ -1655,7 +1656,7 @@ static bool is_exfat(pbr_t *pbr) static bool is_fat32(pbr_t *pbr) { - if (le16_to_cpu(pbr->bpb.f16.num_fat_sectors)) + if (le16_to_cpu(pbr->bpb.fat.num_fat_sectors)) return false; return true; } @@ -1668,7 +1669,7 @@ pbr_t *read_pbr_with_logical_sector(struct super_block *sb, struct buffer_head * if (is_exfat(p_pbr)) logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits; else - logical_sect = get_unaligned_le16(&p_pbr->bpb.f16.sect_size); + logical_sect = get_unaligned_le16(&p_pbr->bpb.fat.sect_size); /* is x a power of 2? * (x) != 0 && (((x) & ((x) - 1)) == 0) @@ -1780,18 +1781,6 @@ s32 fscore_mount(struct super_block *sb) opts->improved_allocation = 0; opts->defrag = 0; ret = mount_exfat(sb, p_pbr); - } else if (is_fat32(p_pbr)) { - if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { - sdfat_log_msg(sb, KERN_ERR, - "not specified filesystem type " - "(media:vfat, opts:%s)", - FS_TYPE_STR[opts->fs_type]); - ret = -EINVAL; - goto free_bh; - } - /* set maximum file size for FAT */ - sb->s_maxbytes = 0xffffffff; - ret = mount_fat32(sb, p_pbr); } else { if (opts->fs_type && opts->fs_type != FS_TYPE_VFAT) { sdfat_log_msg(sb, KERN_ERR, @@ -1803,9 +1792,14 @@ s32 fscore_mount(struct super_block *sb) } /* set maximum file size for FAT */ sb->s_maxbytes = 0xffffffff; - opts->improved_allocation = 0; - opts->defrag = 0; - ret = mount_fat16(sb, p_pbr); + + if (is_fat32(p_pbr)) { + ret = mount_fat32(sb, p_pbr); + } else { + opts->improved_allocation = 0; + opts->defrag = 0; + ret = mount_fat16(sb, p_pbr); + } } free_bh: brelse(tmp_bh); @@ -1817,8 +1811,9 @@ free_bh: /* warn misaligned data data start sector must be a multiple of clu_size */ sdfat_log_msg(sb, KERN_INFO, "detected volume info : %s " - "(bps : %lu, spc : %u, data start : %llu, %s)", + "(%04hX-%04hX, bps : %lu, spc : %u, data start : %llu, %s)", sdfat_get_vol_type_str(fsi->vol_type), + (fsi->vol_id >> 16) & 0xffff, fsi->vol_id & 0xffff, sb->s_blocksize, fsi->sect_per_clus, fsi->data_start_sector, (fsi->data_start_sector & (fsi->sect_per_clus - 1)) ? "misaligned" : "aligned"); @@ -2374,7 +2369,7 @@ s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 cou ep2 = ep; } - fsi->fs_func->set_entry_time(ep, tm_now(SDFAT_SB(sb), &tm), TM_MODIFY); + fsi->fs_func->set_entry_time(ep, tm_now(inode, &tm), TM_MODIFY); fsi->fs_func->set_entry_attr(ep, fid->attr); if (modified) { @@ -2581,7 +2576,7 @@ s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size) ep2 = ep; } - fsi->fs_func->set_entry_time(ep, tm_now(SDFAT_SB(sb), &tm), TM_MODIFY); + fsi->fs_func->set_entry_time(ep, tm_now(inode, &tm), TM_MODIFY); fsi->fs_func->set_entry_attr(ep, fid->attr); /* diff --git a/fs/sdfat/core.h b/fs/sdfat/core.h index 1f8ed5a28ef3e005a13969241954e600a7c7e5e8..a03f8c0a168a204b84013fa72552457298bedebc 100644 --- a/fs/sdfat/core.h +++ b/fs/sdfat/core.h @@ -60,7 +60,15 @@ typedef struct { void *__buf; // __buf should be the last member } ENTRY_SET_CACHE_T; - +/*----------------------------------------------------------------------*/ +/* Inline Functions */ +/*----------------------------------------------------------------------*/ +static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus) +{ + if (clus < CLUS_BASE || fsi->num_clusters <= clus) + return false; + return true; +} /*----------------------------------------------------------------------*/ /* External Function Declarations */ diff --git a/fs/sdfat/core_exfat.c b/fs/sdfat/core_exfat.c index cde77205744556c0611f33ff50520ad11f081fb9..da401bbbed22f8508c4ebef94bdf217938f6bc35 100644 --- a/fs/sdfat/core_exfat.c +++ b/fs/sdfat/core_exfat.c @@ -220,20 +220,27 @@ static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size) ep->size = cpu_to_le64(size); } /* end of exfat_set_entry_size */ + +#define TENS_MS_PER_SEC (100) +#define SEC_TO_TENS_MS(sec) (((sec) & 0x01) ? TENS_MS_PER_SEC : 0) +#define TENS_MS_TO_SEC(tens_ms) (((tens_ms) / TENS_MS_PER_SEC) ? 1 : 0) + static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) { - u16 t = 0x00, d = 0x21, tz = 0x00; + u16 t = 0x00, d = 0x21, tz = 0x00, s = 0x00; FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry; switch (mode) { case TM_CREATE: t = le16_to_cpu(ep->create_time); d = le16_to_cpu(ep->create_date); + s = TENS_MS_TO_SEC(ep->create_time_ms); tz = ep->create_tz; break; case TM_MODIFY: t = le16_to_cpu(ep->modify_time); d = le16_to_cpu(ep->modify_date); + s = TENS_MS_TO_SEC(ep->modify_time_ms); tz = ep->modify_tz; break; case TM_ACCESS: @@ -244,7 +251,7 @@ static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) } tp->tz.value = tz; - tp->sec = (t & 0x001F) << 1; + tp->sec = ((t & 0x001F) << 1) + s; tp->min = (t >> 5) & 0x003F; tp->hour = (t >> 11); tp->day = (d & 0x001F); @@ -263,12 +270,14 @@ static void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) switch (mode) { case TM_CREATE: ep->create_time = cpu_to_le16(t); + ep->create_time_ms = SEC_TO_TENS_MS(tp->sec); ep->create_date = cpu_to_le16(d); ep->create_tz = tp->tz.value; break; case TM_MODIFY: ep->modify_time = cpu_to_le16(t); ep->modify_date = cpu_to_le16(d); + ep->modify_time_ms = (tp->sec & 0x1) ? TENS_MS_PER_SEC : 0; ep->modify_tz = tp->tz.value; break; case TM_ACCESS: @@ -286,12 +295,10 @@ static void __init_file_entry(struct super_block *sb, FILE_DENTRY_T *ep, u32 typ exfat_set_entry_type((DENTRY_T *) ep, type); - tp = tm_now(SDFAT_SB(sb), &tm); + tp = tm_now_sb(sb, &tm); exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS); - ep->create_time_ms = 0; - ep->modify_time_ms = 0; } /* end of __init_file_entry */ static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size) @@ -1279,7 +1286,7 @@ static s32 exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_r } /* check cluster validation */ - if ((p_chain->dir < 2) && (p_chain->dir >= fsi->num_clusters)) { + if (!is_valid_clus(fsi, p_chain->dir)) { EMSG("%s: invalid start cluster (%u)\n", __func__, p_chain->dir); sdfat_debug_bug_on(1); return -EIO; @@ -1367,9 +1374,13 @@ static s32 exfat_alloc_cluster(struct super_block *sb, u32 num_alloc, CHAIN_T *p } /* check cluster validation */ - if ((hint_clu < CLUS_BASE) && (hint_clu >= fsi->num_clusters)) { - EMSG("%s: hint_cluster is invalid (%u)\n", __func__, hint_clu); - ASSERT(0); + if (!is_valid_clus(fsi, hint_clu)) { + /* "last + 1" can be passed as hint_clu. Otherwise, bug_on */ + if (hint_clu != fsi->num_clusters) { + EMSG("%s: hint_cluster is invalid (%u)\n", + __func__, hint_clu); + sdfat_debug_bug_on(1); + } hint_clu = CLUS_BASE; if (p_chain->flags == 0x03) { if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters)) @@ -1508,43 +1519,53 @@ s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr) pbr64_t *p_bpb = (pbr64_t *)p_pbr; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + fsi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; + fsi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; + fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; + fsi->cluster_size = 1 << fsi->cluster_size_bits; + if (!p_bpb->bsx.num_fats) { sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); return -EINVAL; } - fsi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; - fsi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; - fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; - fsi->cluster_size = 1 << fsi->cluster_size_bits; + if (p_bpb->bsx.num_fats >= 2) { + sdfat_msg(sb, KERN_WARNING, + "unsupported number of FAT structure :%u, try with 1", + p_bpb->bsx.num_fats); + } fsi->num_FAT_sectors = le32_to_cpu(p_bpb->bsx.fat_length); + if (!fsi->num_FAT_sectors) { + sdfat_msg(sb, KERN_ERR, "bogus fat size"); + return -EINVAL; + } fsi->FAT1_start_sector = le32_to_cpu(p_bpb->bsx.fat_offset); - if (p_bpb->bsx.num_fats == 1) - fsi->FAT2_start_sector = fsi->FAT1_start_sector; - else - fsi->FAT2_start_sector = fsi->FAT1_start_sector + fsi->num_FAT_sectors; + fsi->FAT2_start_sector = fsi->FAT1_start_sector; fsi->root_start_sector = le32_to_cpu(p_bpb->bsx.clu_offset); fsi->data_start_sector = fsi->root_start_sector; fsi->num_sectors = le64_to_cpu(p_bpb->bsx.vol_length); - fsi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + 2; + if (!fsi->num_sectors) { + sdfat_msg(sb, KERN_ERR, "bogus number of total sector count"); + return -EINVAL; + } + /* because the cluster index starts with 2 */ + fsi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + CLUS_BASE; - fsi->vol_type = EXFAT; fsi->vol_id = le32_to_cpu(p_bpb->bsx.vol_serial); - fsi->root_dir = le32_to_cpu(p_bpb->bsx.root_cluster); fsi->dentries_in_root = 0; fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); - fsi->vol_flag = (u32) le16_to_cpu(p_bpb->bsx.vol_flags); fsi->clu_srch_ptr = CLUS_BASE; fsi->used_clusters = (u32) ~0; fsi->fs_func = &exfat_fs_func; + fsi->vol_type = EXFAT; fat_ent_ops_init(sb); if (p_bpb->bsx.vol_flags & VOL_DIRTY) { diff --git a/fs/sdfat/core_fat.c b/fs/sdfat/core_fat.c index 5e0a196ae42b1fed1b3629279ba6a77bb74fce75..23c134fc5541a581046a6f6f40641b9ed0b765b7 100644 --- a/fs/sdfat/core_fat.c +++ b/fs/sdfat/core_fat.c @@ -176,7 +176,7 @@ static s32 fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_rel } /* check cluster validation */ - if ((p_chain->dir < 2) && (p_chain->dir >= fsi->num_clusters)) { + if (!is_valid_clus(fsi, p_chain->dir)) { EMSG("%s: invalid start cluster (%u)\n", __func__, p_chain->dir); sdfat_debug_bug_on(1); return -EIO; @@ -479,7 +479,7 @@ static void __init_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, u32 type, ep->start_clu_hi = cpu_to_le16(CLUSTER_16(start_clu >> 16)); ep->size = 0; - tp = tm_now(SDFAT_SB(sb), &tm); + tp = tm_now_sb(sb, &tm); fat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); fat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); ep->access_date = 0; @@ -1238,36 +1238,70 @@ static FS_FUNC_T amap_fat_fs_func = { .get_au_stat = amap_get_au_stat, }; -s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) +static s32 mount_fat_common(struct super_block *sb, FS_INFO_T *fsi, + bpb_t *p_bpb, u32 root_sects) { - s32 num_root_sectors; - bpb16_t *p_bpb = &(p_pbr->bpb.f16); - FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + bool fat32 = root_sects == 0 ? true : false; - if (!p_bpb->num_fats) { - sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); + fsi->sect_per_clus = p_bpb->sect_per_clus; + if (!is_power_of_2(fsi->sect_per_clus)) { + sdfat_msg(sb, KERN_ERR, "bogus sectors per cluster %u", + fsi->sect_per_clus); return -EINVAL; } - num_root_sectors = get_unaligned_le16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS; - num_root_sectors = ((num_root_sectors-1) >> sb->s_blocksize_bits) + 1; - - fsi->sect_per_clus = p_bpb->sect_per_clus; fsi->sect_per_clus_bits = ilog2(p_bpb->sect_per_clus); fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; fsi->cluster_size = 1 << fsi->cluster_size_bits; + fsi->dentries_per_clu = 1 << + (fsi->cluster_size_bits - DENTRY_SIZE_BITS); + + fsi->vol_flag = VOL_CLEAN; + fsi->clu_srch_ptr = CLUS_BASE; + fsi->used_clusters = (u32)~0; + fsi->fs_func = &fat_fs_func; fsi->num_FAT_sectors = le16_to_cpu(p_bpb->num_fat_sectors); + if (fat32) { + u32 fat32_len = le32_to_cpu(p_bpb->f32.num_fat32_sectors); + + if (fat32_len) { + fsi->num_FAT_sectors = fat32_len; + } else if (fsi->num_FAT_sectors) { + /* SPEC violation for compatibility */ + sdfat_msg(sb, KERN_WARNING, + "no fatsz32, try with fatsz16: %u", + fsi->num_FAT_sectors); + } + } + + if (!fsi->num_FAT_sectors) { + sdfat_msg(sb, KERN_ERR, "bogus fat size"); + return -EINVAL; + } + + if (!p_bpb->num_fats) { + sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); + return -EINVAL; + } + + if (p_bpb->num_fats > 2) { + sdfat_msg(sb, KERN_WARNING, + "unsupported number of FAT structure :%u, try with 2", + p_bpb->num_fats); + } fsi->FAT1_start_sector = le16_to_cpu(p_bpb->num_reserved); if (p_bpb->num_fats == 1) fsi->FAT2_start_sector = fsi->FAT1_start_sector; else - fsi->FAT2_start_sector = fsi->FAT1_start_sector + fsi->num_FAT_sectors; + fsi->FAT2_start_sector = fsi->FAT1_start_sector + + fsi->num_FAT_sectors; fsi->root_start_sector = fsi->FAT2_start_sector + fsi->num_FAT_sectors; - fsi->data_start_sector = fsi->root_start_sector + num_root_sectors; + fsi->data_start_sector = fsi->root_start_sector + root_sects; + /* SPEC violation for compatibility */ fsi->num_sectors = get_unaligned_le16(p_bpb->num_sectors); if (!fsi->num_sectors) fsi->num_sectors = le32_to_cpu(p_bpb->num_huge_sectors); @@ -1277,15 +1311,20 @@ s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) return -EINVAL; } - fsi->num_clusters = (u32)((fsi->num_sectors - fsi->data_start_sector) >> fsi->sect_per_clus_bits) + CLUS_BASE; /* because the cluster index starts with 2 */ + fsi->num_clusters = (u32)((fsi->num_sectors - fsi->data_start_sector) >> + fsi->sect_per_clus_bits) + CLUS_BASE; - fsi->vol_type = FAT16; - if (fsi->num_clusters < FAT12_THRESHOLD) - fsi->vol_type = FAT12; + return 0; +} - fsi->vol_id = get_unaligned_le32(p_bpb->vol_serial); +s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) +{ + u32 num_root_sectors; + bpb_t *p_bpb = &(p_pbr->bpb.fat); + FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); + fsi->vol_id = get_unaligned_le32(p_bpb->f16.vol_serial); fsi->root_dir = 0; fsi->dentries_in_root = get_unaligned_le16(p_bpb->num_root_entries); if (!fsi->dentries_in_root) { @@ -1294,16 +1333,18 @@ s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr) return -EINVAL; } - fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); + num_root_sectors = fsi->dentries_in_root << DENTRY_SIZE_BITS; + num_root_sectors = ((num_root_sectors - 1) >> sb->s_blocksize_bits) + 1; - fsi->vol_flag = VOL_CLEAN; - fsi->clu_srch_ptr = 2; - fsi->used_clusters = (u32) ~0; + if (mount_fat_common(sb, fsi, p_bpb, num_root_sectors)) + return -EINVAL; - fsi->fs_func = &fat_fs_func; + fsi->vol_type = FAT16; + if (fsi->num_clusters < FAT12_THRESHOLD) + fsi->vol_type = FAT12; fat_ent_ops_init(sb); - if (p_bpb->state & FAT_VOL_DIRTY) { + if (p_bpb->f16.state & FAT_VOL_DIRTY) { fsi->vol_flag |= VOL_DIRTY; sdfat_log_msg(sb, KERN_WARNING, "Volume was not properly " "unmounted. Some data may be corrupt. " @@ -1347,67 +1388,26 @@ s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr) pbr32_t *p_bpb = (pbr32_t *)p_pbr; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); - if (!p_bpb->bpb.num_fats) { - sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); - return -EINVAL; - } - - fsi->sect_per_clus = p_bpb->bpb.sect_per_clus; - fsi->sect_per_clus_bits = ilog2(p_bpb->bpb.sect_per_clus); - fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits; - fsi->cluster_size = 1 << fsi->cluster_size_bits; - - fsi->num_FAT_sectors = le32_to_cpu(p_bpb->bpb.num_fat32_sectors); - - fsi->FAT1_start_sector = le16_to_cpu(p_bpb->bpb.num_reserved); - if (p_bpb->bpb.num_fats == 1) - fsi->FAT2_start_sector = fsi->FAT1_start_sector; - else - fsi->FAT2_start_sector = fsi->FAT1_start_sector + fsi->num_FAT_sectors; - - fsi->root_start_sector = fsi->FAT2_start_sector + fsi->num_FAT_sectors; - fsi->data_start_sector = fsi->root_start_sector; - - /* SPEC violation for compatibility */ - fsi->num_sectors = get_unaligned_le16(p_bpb->bpb.num_sectors); - if (!fsi->num_sectors) - fsi->num_sectors = le32_to_cpu(p_bpb->bpb.num_huge_sectors); - - /* 2nd check */ - if (!fsi->num_sectors) { - sdfat_msg(sb, KERN_ERR, "bogus number of total sector count"); - return -EINVAL; - } - - fsi->num_clusters = (u32)((fsi->num_sectors - fsi->data_start_sector) >> fsi->sect_per_clus_bits) + CLUS_BASE; - /* because the cluster index starts with 2 */ - - fsi->vol_type = FAT32; fsi->vol_id = get_unaligned_le32(p_bpb->bsx.vol_serial); - - fsi->root_dir = le32_to_cpu(p_bpb->bpb.root_cluster); + fsi->root_dir = le32_to_cpu(p_bpb->bpb.f32.root_cluster); fsi->dentries_in_root = 0; - fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS); - fsi->vol_flag = VOL_CLEAN; - fsi->clu_srch_ptr = 2; - fsi->used_clusters = (u32) ~0; + if (mount_fat_common(sb, fsi, &p_bpb->bpb, 0)) + return -EINVAL; - fsi->fs_func = &fat_fs_func; + /* Should be initialized before calling amap_create() */ + fsi->vol_type = FAT32; + fat_ent_ops_init(sb); /* Delayed / smart allocation related init */ fsi->reserved_clusters = 0; - /* Should be initialized before calling amap_create() */ - fat_ent_ops_init(sb); - /* AU Map Creation */ if (SDFAT_SB(sb)->options.improved_allocation & SDFAT_ALLOC_SMART) { u32 hidden_sectors = le32_to_cpu(p_bpb->bpb.num_hid_sectors); u32 calc_hid_sect = 0; int ret; - /* calculate hidden sector size */ calc_hid_sect = __calc_hidden_sect(sb); if (calc_hid_sect != hidden_sectors) { diff --git a/fs/sdfat/fatent.c b/fs/sdfat/fatent.c index fca32a50d33636dea50539964859e160be56cc5d..442a3797fd6e0192ef8198045ce104c73742d1df 100644 --- a/fs/sdfat/fatent.c +++ b/fs/sdfat/fatent.c @@ -355,13 +355,6 @@ static inline bool is_reserved_clus(u32 clus) return false; } -static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus) -{ - if (clus < CLUS_BASE || fsi->num_clusters <= clus) - return false; - return true; -} - s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); diff --git a/fs/sdfat/misc.c b/fs/sdfat/misc.c index ac1de710b58a2b978f1196a2a06caaa6b39510f6..ce08c594f0cb7c2fac125b3b0064c712223ea6cf 100644 --- a/fs/sdfat/misc.c +++ b/fs/sdfat/misc.c @@ -55,15 +55,6 @@ /************************************************************************* * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) -#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) -#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC) -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ - /* EMPTY */ -#endif - - #ifdef CONFIG_SDFAT_UEVENT static struct kobject sdfat_uevent_kobj; @@ -94,6 +85,10 @@ void sdfat_uevent_ro_remount(struct super_block *sb) char major[16], minor[16]; char *envp[] = { major, minor, NULL }; + /* Do not trigger uevent if a device has been ejected */ + if (fsapi_check_bdi_valid(sb)) + return; + snprintf(major, sizeof(major), "MAJOR=%d", MAJOR(bd_dev)); snprintf(minor, sizeof(minor), "MINOR=%d", MINOR(bd_dev)); @@ -127,7 +122,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) pr_err("[SDFAT](%s[%d:%d]):ERR: %pV\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); #ifdef CONFIG_SDFAT_SUPPORT_STLOG - if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { + if (opts->errors == SDFAT_ERRORS_RO && !sb_rdonly(sb)) { ST_LOG("[SDFAT](%s[%d:%d]):ERR: %pV\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); } @@ -138,8 +133,8 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) if (opts->errors == SDFAT_ERRORS_PANIC) { panic("[SDFAT](%s[%d:%d]): fs panic from previous error\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); - } else if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { - sb->s_flags |= MS_RDONLY; + } else if (opts->errors == SDFAT_ERRORS_RO && !sb_rdonly(sb)) { + sb->s_flags |= SB_RDONLY; sdfat_statistics_set_mnt_ro(); pr_err("[SDFAT](%s[%d:%d]): Filesystem has been set " "read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); @@ -333,12 +328,12 @@ void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, tp->Year = year; } -TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp) +TIMESTAMP_T *tm_now(struct inode *inode, TIMESTAMP_T *tp) { - sdfat_timespec_t ts = CURRENT_TIME_SEC; + sdfat_timespec_t ts = current_time(inode); DATE_TIME_T dt; - sdfat_time_unix2fat(sbi, &ts, &dt); + sdfat_time_unix2fat(SDFAT_SB(inode->i_sb), &ts, &dt); tp->year = dt.Year; tp->mon = dt.Month; diff --git a/fs/sdfat/mpage.c b/fs/sdfat/mpage.c index f550fbb2204a841837a10ea53a0a0a49076af791..4f5037768fa5dea39919d72b7c7224535ef974ec 100644 --- a/fs/sdfat/mpage.c +++ b/fs/sdfat/mpage.c @@ -70,6 +70,9 @@ #ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE +#define MIN_ALIGNED_SIZE (PAGE_SIZE) +#define MIN_ALIGNED_SIZE_MASK (MIN_ALIGNED_SIZE - 1) + /************************************************************************* * INNER FUNCTIONS FOR FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ @@ -97,6 +100,14 @@ static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_ { unmap_underlying_metadata(bdev, block); } + +static inline int wbc_to_write_flags(struct writeback_control *wbc) +{ + if (wbc->sync_mode == WB_SYNC_ALL) + return WRITE_SYNC; + + return 0; +} #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) @@ -236,6 +247,9 @@ static inline unsigned int __calc_size_to_align(struct super_block *sb) if (aligned && (max_sectors & (aligned - 1))) aligned = 0; + + if (aligned && aligned < (MIN_ALIGNED_SIZE >> SECTOR_SIZE_BITS)) + aligned = 0; out: return aligned; } @@ -248,6 +262,24 @@ struct mpage_data { unsigned int size_to_align; }; +/* + * After completing I/O on a page, call this routine to update the page + * flags appropriately + */ +static void __page_write_endio(struct page *page, int err) +{ + if (err) { + struct address_space *mapping; + + SetPageError(page); + mapping = page_mapping(page); + if (mapping) + mapping_set_error(mapping, err); + } + __dfr_writepage_end_io(page); + end_page_writeback(page); +} + /* * I/O completion handler for multipage BIOs. * @@ -262,25 +294,37 @@ struct mpage_data { */ static void __mpage_write_end_io(struct bio *bio, int err) { - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + struct bio_vec *bv; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) + struct bvec_iter_all iter_all; ASSERT(bio_data_dir(bio) == WRITE); /* only write */ + /* Use bio_for_each_segemnt_all() to support multi-page bvec */ + bio_for_each_segment_all(bv, bio, iter_all) + __page_write_endio(bv->bv_page, err); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) + struct bvec_iter_all iter_all; + int i; + + ASSERT(bio_data_dir(bio) == WRITE); /* only write */ + + /* Use bio_for_each_segemnt_all() to support multi-page bvec */ + bio_for_each_segment_all(bv, bio, i, iter_all) + __page_write_endio(bv->bv_page, err); +#else + ASSERT(bio_data_dir(bio) == WRITE); /* only write */ + bv = bio->bi_io_vec + bio->bi_vcnt - 1; + do { - struct page *page = bvec->bv_page; - - if (--bvec >= bio->bi_io_vec) - prefetchw(&bvec->bv_page->flags); - if (err) { - SetPageError(page); - if (page->mapping) - mapping_set_error(page->mapping, err); - } + struct page *page = bv->bv_page; - __dfr_writepage_end_io(page); + if (--bv >= bio->bi_io_vec) + prefetchw(&bv->bv_page->flags); - end_page_writeback(page); - } while (bvec >= bio->bi_io_vec); + __page_write_endio(page, err); + } while (bv >= bio->bi_io_vec); +#endif bio_put(bio); } @@ -312,6 +356,65 @@ mpage_alloc(struct block_device *bdev, return bio; } + +#if IS_BUILTIN(CONFIG_SDFAT_FS) +#define __write_boundary_block write_boundary_block +#define sdfat_buffer_heads_over_limit buffer_heads_over_limit +#else + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +/* + * Called when we've recently written block `bblock', and it is known that + * `bblock' was for a buffer_boundary() buffer. This means that the block at + * `bblock + 1' is probably a dirty indirect block. Hunt it down and, if it's + * dirty, schedule it for IO. So that indirects merge nicely with their data. + */ +static void __write_boundary_block(struct block_device *bdev, + sector_t bblock, unsigned int blocksize) +{ + struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize); + + if (bh) { + if (buffer_dirty(bh)) + ll_rw_block(REQ_OP_WRITE, 0, 1, &bh); + put_bh(bh); + } +} +#else +#warning "Need an alternative of write_boundary_block function" +#define __write_boundary_block write_boundary_block +#endif + +#warning "sdfat could not check buffer_heads_over_limit on module. Assumed zero" +#define sdfat_buffer_heads_over_limit (0) +#endif + +static void clean_buffers(struct page *page, unsigned int first_unmapped) +{ + unsigned int buffer_counter = 0; + struct buffer_head *bh, *head; + + if (!page_has_buffers(page)) + return; + head = page_buffers(page); + bh = head; + + do { + if (buffer_counter++ == first_unmapped) + break; + clear_buffer_dirty(bh); + bh = bh->b_this_page; + } while (bh != head); + + /* + * we cannot drop the bh if the page is not uptodate or a concurrent + * readpage would fail to serialize with the bh and it would read from + * disk before we reach the platter. + */ + if (sdfat_buffer_heads_over_limit && PageUptodate(page)) + try_to_free_buffers(page); +} + static int sdfat_mpage_writepage(struct page *page, struct writeback_control *wbc, void *data) { @@ -335,6 +438,7 @@ static int sdfat_mpage_writepage(struct page *page, loff_t i_size = i_size_read(inode); unsigned long end_index = i_size >> PAGE_SHIFT; int ret = 0; + int op_flags = wbc_to_write_flags(wbc); if (page_has_buffers(page)) { struct buffer_head *head = page_buffers(page); @@ -490,22 +594,25 @@ page_is_mapped: */ if (bio) { if (mpd->last_block_in_bio != blocks[0] - 1) { - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); } else if (mpd->size_to_align) { unsigned int mask = mpd->size_to_align - 1; sector_t max_end_block = (__sdfat_bio_sector(bio) & ~(mask)) + mask; - if ((__sdfat_bio_size(bio) != (1 << (mask + 1))) && + if ((__sdfat_bio_size(bio) & MIN_ALIGNED_SIZE_MASK) && (mpd->last_block_in_bio == max_end_block)) { + int op_nomerge = op_flags | REQ_NOMERGE; + MMSG("%s(inode:%p) alignment mpage_bio_submit" - "(start:%u, len:%u aligned:%u)\n", + "(start:%u, len:%u size:%u aligned:%u)\n", __func__, inode, (unsigned int)__sdfat_bio_sector(bio), (unsigned int)(mpd->last_block_in_bio - __sdfat_bio_sector(bio) + 1), + (unsigned int)__sdfat_bio_size(bio), (unsigned int)mpd->size_to_align); - bio = mpage_bio_submit_write(REQ_NOMERGE, bio); + bio = mpage_bio_submit_write(op_nomerge, bio); } } } @@ -525,7 +632,7 @@ alloc_new: */ length = first_unmapped << blkbits; if (bio_add_page(bio, page, length, 0) < length) { - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); goto alloc_new; } @@ -533,26 +640,7 @@ alloc_new: * OK, we have our BIO, so we can now mark the buffers clean. Make * sure to only clean buffers which we know we'll be writing. */ - if (page_has_buffers(page)) { - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh = head; - unsigned int buffer_counter = 0; - - do { - if (buffer_counter++ == first_unmapped) - break; - clear_buffer_dirty(bh); - bh = bh->b_this_page; - } while (bh != head); - - /* - * we cannot drop the bh if the page is not uptodate - * or a concurrent readpage would fail to serialize with the bh - * and it would read from disk before we reach the platter. - */ - if (buffer_heads_over_limit && PageUptodate(page)) - try_to_free_buffers(page); - } + clean_buffers(page, first_unmapped); BUG_ON(PageWriteback(page)); set_page_writeback(page); @@ -579,9 +667,9 @@ alloc_new: unlock_page(page); if (boundary || (first_unmapped != blocks_per_page)) { - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); if (boundary_block) { - write_boundary_block(boundary_bdev, + __write_boundary_block(boundary_bdev, boundary_block, 1 << blkbits); } } else { @@ -592,7 +680,7 @@ alloc_new: confused: if (bio) - bio = mpage_bio_submit_write(0, bio); + bio = mpage_bio_submit_write(op_flags, bio); if (mpd->use_writepage) { ret = mapping->a_ops->writepage(page, wbc); @@ -625,8 +713,11 @@ int sdfat_mpage_writepages(struct address_space *mapping, BUG_ON(!get_block); blk_start_plug(&plug); ret = write_cache_pages(mapping, wbc, sdfat_mpage_writepage, &mpd); - if (mpd.bio) - mpage_bio_submit_write(0, mpd.bio); + if (mpd.bio) { + int op_flags = wbc_to_write_flags(wbc); + + mpage_bio_submit_write(op_flags, mpd.bio); + } blk_finish_plug(&plug); return ret; } diff --git a/fs/sdfat/sdfat.c b/fs/sdfat/sdfat.c index 37630f662fab327cc85c37caab95f5a438c1ed92..72dfe270856df702b5795be9429d4caa690445c4 100644 --- a/fs/sdfat/sdfat.c +++ b/fs/sdfat/sdfat.c @@ -190,6 +190,14 @@ static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_ { unmap_underlying_metadata(bdev, block); } + +static inline int wbc_to_write_flags(struct writeback_control *wbc) +{ + if (wbc->sync_mode == WB_SYNC_ALL) + return WRITE_SYNC; + + return 0; +} #endif @@ -224,9 +232,12 @@ static int setattr_prepare(struct dentry *dentry, struct iattr *attr) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) -static inline void __sdfat_submit_bio_write(struct bio *bio) +static inline void __sdfat_submit_bio_write(struct bio *bio, + struct writeback_control *wbc) { - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + int write_flags = wbc_to_write_flags(wbc); + + bio_set_op_attrs(bio, REQ_OP_WRITE, write_flags); submit_bio(bio); } @@ -240,9 +251,12 @@ static inline unsigned long __sdfat_init_name_hash(const struct dentry *dentry) return init_name_hash(dentry); } #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) */ -static inline void __sdfat_submit_bio_write(struct bio *bio) +static inline void __sdfat_submit_bio_write(struct bio *bio, + struct writeback_control *wbc) { - submit_bio(WRITE, bio); + int write_flags = wbc_to_write_flags(wbc); + + submit_bio(WRITE | write_flags, bio); } static inline unsigned int __sdfat_full_name_hash(const struct dentry *unused, const char *name, unsigned int len) @@ -289,6 +303,15 @@ static inline int sdfat_remount_syncfs(struct super_block *sb) } #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + /* EMPTY */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) */ +static inline void truncate_inode_pages_final(struct address_space *mapping) +{ + truncate_inode_pages(mapping, 0); +} +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) static inline sector_t __sdfat_bio_sector(struct bio *bio) @@ -904,15 +927,6 @@ static int sdfat_file_fsync(struct file *filp, int datasync) /************************************************************************* * MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) -#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) -#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC) -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */ - /* EMPTY */ -#endif - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) static void sdfat_writepage_end_io(struct bio *bio) { @@ -2186,7 +2200,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp, __lock_super(sb); /* Check if FS_ERROR occurred */ - if (sb->s_flags & MS_RDONLY) { + if (sb_rdonly(sb)) { dfr_err("RDONLY partition (err %d)", -EPERM); __unlock_super(sb); return -EPERM; @@ -2397,7 +2411,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); if (err) @@ -2556,7 +2570,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); SDFAT_I(inode)->fid.size = i_size_read(inode); @@ -2605,7 +2619,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); if (err) @@ -2666,7 +2680,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); err = fsapi_mkdir(dir, (u8 *) dentry->d_name.name, &fid); if (err) @@ -2715,7 +2729,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); - ts = CURRENT_TIME_SEC; + ts = current_time(dir); SDFAT_I(inode)->fid.size = i_size_read(inode); @@ -2760,7 +2774,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; - ts = CURRENT_TIME_SEC; + ts = current_time(old_inode); SDFAT_I(old_inode)->fid.size = i_size_read(old_inode); @@ -2838,7 +2852,7 @@ static int sdfat_cont_expand(struct inode *inode, loff_t size) if (err) return err; - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + inode->i_ctime = inode->i_mtime = current_time(inode); mark_inode_dirty(inode); if (!IS_SYNC(inode)) @@ -3096,7 +3110,7 @@ static void sdfat_truncate(struct inode *inode, loff_t old_size) if (err) goto out; - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + inode->i_ctime = inode->i_mtime = current_time(inode); if (IS_DIRSYNC(inode)) (void) sdfat_sync_inode(inode); else @@ -3524,7 +3538,8 @@ static int sdfat_readpages(struct file *file, struct address_space *mapping, } static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, - sector_t sector, unsigned int length, struct page *page) + sector_t sector, unsigned int length, + struct page *page, struct writeback_control *wbc) { /* Single page bio submit */ struct bio *bio; @@ -3548,7 +3563,7 @@ static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, __sdfat_set_bio_iterate(bio, sector, length, 0, 0); bio->bi_end_io = sdfat_writepage_end_io; - __sdfat_submit_bio_write(bio); + __sdfat_submit_bio_write(bio, wbc); } static int sdfat_writepage(struct page *page, struct writeback_control *wbc) @@ -3683,7 +3698,7 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) sdfat_submit_fullpage_bio(head->b_bdev, head->b_blocknr << (sb->s_blocksize_bits - SECTOR_SIZE_BITS), nr_blocks_towrite << inode->i_blkbits, - page); + page, wbc); unlock_page(page); @@ -3748,7 +3763,7 @@ static int sdfat_check_writable(struct super_block *sb) if (fsapi_check_bdi_valid(sb)) return -EIO; - if (sb->s_flags & MS_RDONLY) + if (sb_rdonly(sb)) return -EROFS; return 0; @@ -3823,7 +3838,7 @@ static int sdfat_write_end(struct file *file, struct address_space *mapping, sdfat_write_failed(mapping, pos+len); if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + inode->i_mtime = inode->i_ctime = current_time(inode); fid->attr |= ATTR_ARCHIVE; mark_inode_dirty(inode); } @@ -4035,7 +4050,7 @@ static struct inode *sdfat_alloc_inode(struct super_block *sb) return &ei->vfs_inode; } -static void sdfat_destroy_inode(struct inode *inode) +static void sdfat_free_inode(struct inode *inode) { if (SDFAT_I(inode)->target) { kfree(SDFAT_I(inode)->target); @@ -4045,6 +4060,28 @@ static void sdfat_destroy_inode(struct inode *inode) kmem_cache_free(sdfat_inode_cachep, SDFAT_I(inode)); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) +/* Use free_inode instead of destroy_inode */ +#define sdfat_destroy_inode (NULL) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) +static void sdfat_i_callback(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + + sdfat_free_inode(inode); +} + +static void sdfat_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, sdfat_i_callback); +} +#else +static void sdfat_destroy_inode(struct inode *inode) +{ + sdfat_free_inode(inode); +} +#endif + static int __sdfat_write_inode(struct inode *inode, int sync) { struct super_block *sb = inode->i_sb; @@ -4080,7 +4117,7 @@ static int sdfat_write_inode(struct inode *inode, struct writeback_control *wbc) static void sdfat_evict_inode(struct inode *inode) { - truncate_inode_pages(&inode->i_data, 0); + truncate_inode_pages_final(&inode->i_data); if (!inode->i_nlink) { loff_t old_size = i_size_read(inode); @@ -4108,23 +4145,8 @@ static void sdfat_evict_inode(struct inode *inode) /* remove_inode_hash(inode); */ } - - -static void sdfat_put_super(struct super_block *sb) +static void sdfat_free_sb_info(struct sdfat_sb_info *sbi) { - struct sdfat_sb_info *sbi = SDFAT_SB(sb); - int err; - - sdfat_log_msg(sb, KERN_INFO, "trying to unmount..."); - - __cancel_delayed_work_sync(sbi); - - if (__is_sb_dirty(sb)) - sdfat_write_super(sb); - - __free_dfr_mem_if_required(sb); - err = fsapi_umount(sb); - if (sbi->nls_disk) { unload_nls(sbi->nls_disk); sbi->nls_disk = NULL; @@ -4139,14 +4161,63 @@ static void sdfat_put_super(struct super_block *sb) sbi->options.iocharset = sdfat_default_iocharset; } + if (sbi->use_vmalloc) { + vfree(sbi); + return; + } + kfree(sbi); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) +static void delayed_free(struct rcu_head *p) +{ + struct sdfat_sb_info *sbi = container_of(p, struct sdfat_sb_info, rcu); + + sdfat_free_sb_info(sbi); +} + +static void __sdfat_destroy_sb_info(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + + call_rcu(&sbi->rcu, delayed_free); +} +#else +static void __sdfat_destroy_sb_info(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + + sdfat_free_sb_info(sbi); sb->s_fs_info = NULL; +} +#endif + +static void sdfat_destroy_sb_info(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); kobject_del(&sbi->sb_kobj); kobject_put(&sbi->sb_kobj); - if (!sbi->use_vmalloc) - kfree(sbi); - else - vfree(sbi); + + __sdfat_destroy_sb_info(sb); +} + +static void sdfat_put_super(struct super_block *sb) +{ + struct sdfat_sb_info *sbi = SDFAT_SB(sb); + int err; + + sdfat_log_msg(sb, KERN_INFO, "trying to unmount..."); + + __cancel_delayed_work_sync(sbi); + + if (__is_sb_dirty(sb)) + sdfat_write_super(sb); + + __free_dfr_mem_if_required(sb); + err = fsapi_umount(sb); + + sdfat_destroy_sb_info(sb); sdfat_log_msg(sb, KERN_INFO, "unmounted successfully! %s", err ? "(with previous I/O errors)" : ""); @@ -4177,7 +4248,7 @@ static void sdfat_write_super(struct super_block *sb) /* flush delayed FAT/DIR dirty */ __flush_delayed_meta(sb, 0); - if (!(sb->s_flags & MS_RDONLY)) + if (!sb_rdonly(sb)) fsapi_sync_fs(sb, 0); __unlock_super(sb); @@ -4305,7 +4376,8 @@ static int sdfat_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bavail = info.FreeClusters; buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); - buf->f_namelen = 260; + /* Unicode utf8 255 characters */ + buf->f_namelen = MAX_NAME_LENGTH * MAX_CHARSET_SIZE; return 0; } @@ -4317,7 +4389,7 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data) struct sdfat_sb_info *sbi = SDFAT_SB(sb); FS_INFO_T *fsi = &(sbi->fsi); - *flags |= MS_NODIRATIME; + *flags |= SB_NODIRATIME; prev_sb_flags = sb->s_flags; @@ -4326,8 +4398,8 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data) fsapi_set_vol_flags(sb, VOL_CLEAN, 1); sdfat_log_msg(sb, KERN_INFO, "re-mounted(%s->%s), eio=0x%x, Opts: %s", - (prev_sb_flags & MS_RDONLY) ? "ro" : "rw", - (*flags & MS_RDONLY) ? "ro" : "rw", + (prev_sb_flags & SB_RDONLY) ? "ro" : "rw", + (*flags & SB_RDONLY) ? "ro" : "rw", fsi->prev_eio, orig_data); kfree(orig_data); return 0; @@ -4390,7 +4462,11 @@ static int __sdfat_show_options(struct seq_file *m, struct super_block *sb) static const struct super_operations sdfat_sops = { .alloc_inode = sdfat_alloc_inode, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) + .free_inode = sdfat_free_inode, +#else .destroy_inode = sdfat_destroy_inode, +#endif .write_inode = sdfat_write_inode, .evict_inode = sdfat_evict_inode, .put_super = sdfat_put_super, @@ -4833,7 +4909,7 @@ static int sdfat_read_root(struct inode *inode) FS_INFO_T *fsi = &(sbi->fsi); DIR_ENTRY_T info; - ts = CURRENT_TIME_SEC; + ts = current_time(inode); SDFAT_I(inode)->fid.dir.dir = fsi->root_dir; SDFAT_I(inode)->fid.dir.flags = 0x01; @@ -4917,11 +4993,18 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent) mutex_init(&sbi->s_vlock); sb->s_fs_info = sbi; - sb->s_flags |= MS_NODIRATIME; + sb->s_flags |= SB_NODIRATIME; sb->s_magic = SDFAT_SUPER_MAGIC; sb->s_op = &sdfat_sops; ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) + sb->s_time_gran = NSEC_PER_SEC; /* the same with default */ + sb->s_time_min = SDFAT_MIN_TIMESTAMP_SECS; + sb->s_time_max = SDFAT_MAX_TIMESTAMP_SECS; +#endif + err = parse_options(sb, data, silent, &debug, &sbi->options); if (err) { sdfat_log_msg(sb, KERN_ERR, "failed to parse options"); @@ -5068,6 +5151,13 @@ static int __init sdfat_init_inodecache(void) static void sdfat_destroy_inodecache(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); +#endif kmem_cache_destroy(sdfat_inode_cachep); } @@ -5216,6 +5306,13 @@ error: static void __exit exit_sdfat_fs(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); +#endif sdfat_uevent_uninit(); sdfat_statistics_uninit(); diff --git a/fs/sdfat/sdfat.h b/fs/sdfat/sdfat.h index 60f7811c7b99ebb2bdaae8ffff9c65bd75c5fbd7..8a18aa5b798e852f501b29210e456eff2d2211b4 100644 --- a/fs/sdfat/sdfat.h +++ b/fs/sdfat/sdfat.h @@ -142,6 +142,9 @@ struct sdfat_sb_info { struct mutex s_vlock; /* volume lock */ int use_vmalloc; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + struct rcu_head rcu; +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) int s_dirt; struct mutex s_lock; /* superblock lock */ @@ -215,6 +218,30 @@ typedef struct timespec64 sdfat_timespec_t; typedef struct timespec sdfat_timespec_t; #endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */ +/* + * sb->s_flags. Note that these mirror the equivalent MS_* flags where + * represented in both. + */ +#define SB_RDONLY 1 /* Mount read-only */ +#define SB_NODIRATIME 2048 /* Do not update directory access times */ +static inline bool sb_rdonly(const struct super_block *sb) +{ + return sb->s_flags & MS_RDONLY; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) + /* EMPTY */ +#else +static inline sdfat_timespec_t current_time(struct inode *inode) +{ + return CURRENT_TIME_SEC; +} +#endif /* * FIXME : needs on-disk-slot in-memory data */ @@ -387,7 +414,14 @@ extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, DATE_TIME_T *tp); extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, DATE_TIME_T *tp); -extern TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tm); +extern TIMESTAMP_T *tm_now(struct inode *inode, TIMESTAMP_T *tm); +static inline TIMESTAMP_T *tm_now_sb(struct super_block *sb, TIMESTAMP_T *tm) +{ + struct inode fake_inode; + + fake_inode.i_sb = sb; + return tm_now(&fake_inode, tm); +} #ifdef CONFIG_SDFAT_DEBUG diff --git a/fs/sdfat/sdfat_fs.h b/fs/sdfat/sdfat_fs.h index b012e406fb23f161246e9a9fed0f7ccb53bcf68a..5debaa9617b219b5106da1475eb24aaa6746476a 100644 --- a/fs/sdfat/sdfat_fs.h +++ b/fs/sdfat/sdfat_fs.h @@ -145,6 +145,13 @@ #define CS_PBR_SECTOR 1 #define CS_DEFAULT 2 +/* time min/max */ +/* Jan 1 GMT 00:00:00 1980 */ +#define SDFAT_MIN_TIMESTAMP_SECS 315532800LL +/* Dec 31 GMT 23:59:59 2107 */ +#define SDFAT_MAX_TIMESTAMP_SECS 4354819199LL + + /* * ioctl command */ @@ -179,7 +186,7 @@ /* On-Disk Type Definitions */ /*----------------------------------------------------------------------*/ -/* FAT12/16 BIOS parameter block (64 bytes) */ +/* FAT12/16/32 BIOS parameter block (64 bytes) */ typedef struct { __u8 jmp_boot[3]; __u8 oem_name[8]; @@ -197,41 +204,28 @@ typedef struct { __le32 num_hid_sectors; /* . */ __le32 num_huge_sectors; - __u8 phy_drv_no; - __u8 state; /* used by WindowsNT for mount state */ - __u8 ext_signature; - __u8 vol_serial[4]; - __u8 vol_label[11]; - __u8 vol_type[8]; - __le16 dummy; -} bpb16_t; - -/* FAT32 BIOS parameter block (64 bytes) */ -typedef struct { - __u8 jmp_boot[3]; - __u8 oem_name[8]; - - __u8 sect_size[2]; /* unaligned */ - __u8 sect_per_clus; - __le16 num_reserved; - __u8 num_fats; - __u8 num_root_entries[2]; /* unaligned */ - __u8 num_sectors[2]; /* unaligned */ - __u8 media_type; - __le16 num_fat_sectors; /* zero */ - __le16 sectors_in_track; - __le16 num_heads; - __le32 num_hid_sectors; /* . */ - __le32 num_huge_sectors; - - __le32 num_fat32_sectors; - __le16 ext_flags; - __u8 fs_version[2]; - __le32 root_cluster; /* . */ - __le16 fsinfo_sector; - __le16 backup_sector; - __le16 reserved[6]; /* . */ -} bpb32_t; + union { + struct { + __u8 phy_drv_no; + __u8 state; /* used by WinNT for mount state */ + __u8 ext_signature; + __u8 vol_serial[4]; + __u8 vol_label[11]; + __u8 vol_type[8]; + __le16 nouse; + } f16; + + struct { + __le32 num_fat32_sectors; + __le16 ext_flags; + __u8 fs_version[2]; + __le32 root_cluster; /* . */ + __le16 fsinfo_sector; + __le16 backup_sector; + __le16 reserved[6]; /* . */ + } f32; + }; +} bpb_t; /* FAT32 EXTEND BIOS parameter block (32 bytes) */ typedef struct { @@ -273,12 +267,12 @@ typedef struct { /* FAT32 PBR (64 bytes) */ typedef struct { - bpb16_t bpb; + bpb_t bpb; } pbr16_t; /* FAT32 PBR[BPB+BSX] (96 bytes) */ typedef struct { - bpb32_t bpb; + bpb_t bpb; bsx32_t bsx; } pbr32_t; @@ -292,8 +286,7 @@ typedef struct { typedef struct { union { __u8 raw[64]; - bpb16_t f16; - bpb32_t f32; + bpb_t fat; bpb64_t f64; } bpb; union { diff --git a/fs/sdfat/version.h b/fs/sdfat/version.h index ab0459a38982af11074f74b1324415f7bae76075..92e99621143f0af8c277333ff7024916ee29f047 100644 --- a/fs/sdfat/version.h +++ b/fs/sdfat/version.h @@ -22,4 +22,4 @@ /* PURPOSE : sdFAT File Manager */ /* */ /************************************************************************/ -#define SDFAT_VERSION "2.3.0" +#define SDFAT_VERSION "2.4.5-lineage" diff --git a/fs/sdfat/xattr.c b/fs/sdfat/xattr.c index 40bb850711bebf194f48b609d9f3a0d08e34f903..bd037358b644a06d6e5338e24a97b27dc488b380 100644 --- a/fs/sdfat/xattr.c +++ b/fs/sdfat/xattr.c @@ -79,12 +79,22 @@ ssize_t __sdfat_getxattr(const char *name, void *value, size_t size) * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +#if defined(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static int sdfat_xattr_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *buffer, size_t size, + int flags) +{ + return __sdfat_getxattr(name, buffer, size); +} +#else static int sdfat_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size) { return __sdfat_getxattr(name, buffer, size); } +#endif static int sdfat_xattr_set(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, diff --git a/fs/seq_file.c b/fs/seq_file.c index f48a432ff78fb336c9a8c23ef78c016df798d5e6..7c1e0c043312ac60a19f5d070a0c68608cdd2bca 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -12,21 +12,11 @@ #include #include #include +#include #include #include - -/* - * seq_files have a buffer which can may overflow. When this happens a larger - * buffer is reallocated and all the data will be printed again. - * The overflow state is true when m->count == m->size. - */ -static bool seq_overflow(struct seq_file *m) -{ - return m->count == m->size; -} - static void seq_set_overflow(struct seq_file *m) { m->count = m->size; @@ -37,6 +27,9 @@ static void *seq_buf_alloc(unsigned long size) void *buf; gfp_t gfp = GFP_KERNEL; + if (unlikely(size > MAX_RW_COUNT)) + return NULL; + /* * For high order allocations, use __GFP_NORETRY to avoid oom-killing - * it's better to fall back to vmalloc() than to kill things. For small @@ -134,7 +127,7 @@ static int traverse(struct seq_file *m, loff_t offset) error = 0; m->count = 0; } - if (seq_overflow(m)) + if (seq_has_overflowed(m)) goto Eoverflow; if (pos + m->count > offset) { m->from = offset - pos; @@ -279,7 +272,7 @@ Fill: break; } err = m->op->show(m, p); - if (seq_overflow(m) || err) { + if (seq_has_overflowed(m) || err) { m->count = offs; if (likely(err <= 0)) break; @@ -963,3 +956,57 @@ struct hlist_node *seq_hlist_next_rcu(void *v, return rcu_dereference(node->next); } EXPORT_SYMBOL(seq_hlist_next_rcu); + +/** + * seq_hlist_start_precpu - start an iteration of a percpu hlist array + * @head: pointer to percpu array of struct hlist_heads + * @cpu: pointer to cpu "cursor" + * @pos: start position of sequence + * + * Called at seq_file->op->start(). + */ +struct hlist_node * +seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos) +{ + struct hlist_node *node; + + for_each_possible_cpu(*cpu) { + hlist_for_each(node, per_cpu_ptr(head, *cpu)) { + if (pos-- == 0) + return node; + } + } + return NULL; +} +EXPORT_SYMBOL(seq_hlist_start_percpu); + +/** + * seq_hlist_next_percpu - move to the next position of the percpu hlist array + * @v: pointer to current hlist_node + * @head: pointer to percpu array of struct hlist_heads + * @cpu: pointer to cpu "cursor" + * @pos: start position of sequence + * + * Called at seq_file->op->next(). + */ +struct hlist_node * +seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, + int *cpu, loff_t *pos) +{ + struct hlist_node *node = v; + + ++*pos; + + if (node->next) + return node->next; + + for (*cpu = cpumask_next(*cpu, cpu_possible_mask); *cpu < nr_cpu_ids; + *cpu = cpumask_next(*cpu, cpu_possible_mask)) { + struct hlist_head *bucket = per_cpu_ptr(head, *cpu); + + if (!hlist_empty(bucket)) + return bucket->first; + } + return NULL; +} +EXPORT_SYMBOL(seq_hlist_next_percpu); diff --git a/fs/timerfd.c b/fs/timerfd.c index ea2d774ca9613f9e1674408950944649f2af3ab4..1a65e017048e3fc7d99296a87eea85f67f10a02a 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -334,6 +334,11 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) clockid != CLOCK_POWEROFF_ALARM)) return -EINVAL; + if (!capable(CAP_WAKE_ALARM) && + (clockid == CLOCK_REALTIME_ALARM || + clockid == CLOCK_BOOTTIME_ALARM)) + return -EPERM; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -377,6 +382,11 @@ static int do_timerfd_settime(int ufd, int flags, return ret; ctx = f.file->private_data; + if (!capable(CAP_WAKE_ALARM) && isalarm(ctx)) { + fdput(f); + return -EPERM; + } + timerfd_setup_cancel(ctx, flags); /* diff --git a/include/linux/atomic.h b/include/linux/atomic.h index fef3a809e7cf04e6b7a41d81685782ec029638ce..411cc4b266520f376befa288d9040427b8e4b001 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -39,6 +39,55 @@ static inline void __deprecated smp_mb__after_atomic_dec(void) } #endif +/* atomic_cmpxchg_relaxed */ +#ifndef atomic_cmpxchg_relaxed +#define atomic_cmpxchg_relaxed atomic_cmpxchg +#define atomic_cmpxchg_acquire atomic_cmpxchg +#define atomic_cmpxchg_release atomic_cmpxchg + +#else /* atomic_cmpxchg_relaxed */ + +#ifndef atomic_cmpxchg_acquire +#define atomic_cmpxchg_acquire(...) \ + __atomic_op_acquire(atomic_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic_cmpxchg_release +#define atomic_cmpxchg_release(...) \ + __atomic_op_release(atomic_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic_cmpxchg +#define atomic_cmpxchg(...) \ + __atomic_op_fence(atomic_cmpxchg, __VA_ARGS__) +#endif +#endif /* atomic_cmpxchg_relaxed */ + +/* these were introduced together, so just a single check is enough */ +#ifndef atomic_try_cmpxchg_acquire +#ifndef atomic_try_cmpxchg +#define __atomic_try_cmpxchg(type, _p, _po, _n) \ +({ \ + typeof(_po) __po = (_po); \ + typeof(*(_po)) __r, __o = *__po; \ + __r = atomic_cmpxchg##type((_p), __o, (_n)); \ + if (unlikely(__r != __o)) \ + *__po = __r; \ + likely(__r == __o); \ +}) + +#define atomic_try_cmpxchg(_p, _po, _n) __atomic_try_cmpxchg(, _p, _po, _n) +#define atomic_try_cmpxchg_relaxed(_p, _po, _n) __atomic_try_cmpxchg(_relaxed, _p, _po, _n) +#define atomic_try_cmpxchg_acquire(_p, _po, _n) __atomic_try_cmpxchg(_acquire, _p, _po, _n) +#define atomic_try_cmpxchg_release(_p, _po, _n) __atomic_try_cmpxchg(_release, _p, _po, _n) +#else /* atomic_try_cmpxchg */ +#define atomic_try_cmpxchg_relaxed atomic_try_cmpxchg +#define atomic_try_cmpxchg_acquire atomic_try_cmpxchg +#define atomic_try_cmpxchg_release atomic_try_cmpxchg +#endif /* atomic_try_cmpxchg */ + +#endif /* atomic_try_cmpxchg_acquire */ + /** * atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 2ad7b860f06232d76ae5a4f208d081a17825a9ae..546ac1cbae9b4e7cd7c3aed1045f182cb16be3d1 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -394,8 +394,8 @@ union ceph_mds_request_args { struct { __u8 rule; /* currently fcntl or flock */ __u8 type; /* shared, exclusive, remove*/ + __le64 owner; /* owner of the lock */ __le64 pid; /* process id requesting the lock */ - __le64 pid_namespace; __le64 start; /* initial location to lock */ __le64 length; /* num bytes to lock from start */ __u8 wait; /* will caller wait for lock to become available? */ @@ -505,8 +505,8 @@ struct ceph_filelock { __le64 start;/* file offset to start lock at */ __le64 length; /* num bytes to lock; 0 for all following start */ __le64 client; /* which client holds the lock */ + __le64 owner; /* owner the lock */ __le64 pid; /* process id holding the lock on the client */ - __le64 pid_namespace; __u8 type; /* shared lock, exclusive lock, or unlock */ } __attribute__ ((packed)); diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index d08e4d2a9b92550af4b395bb62d101873d9d7731..7abda3b903db530d05ebc25eefe3d1680bb10138 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -22,6 +22,14 @@ typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t; */ #define cpumask_bits(maskp) ((maskp)->bits) +/** + * cpumask_pr_args - printf args to output a cpumask + * @maskp: cpumask to be printed + * + * Can be used to provide arguments for '%*pb[l]' when printing a cpumask. + */ +#define cpumask_pr_args(maskp) nr_cpu_ids, cpumask_bits(maskp) + #if NR_CPUS == 1 #define nr_cpu_ids 1 #else diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 671ab0218edbe06174b8e12c2dff9468b867aa8b..5b94a873ad89611d112849c2259b736b1591dc6c 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -328,6 +328,11 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq) return ret; } +static inline unsigned d_count(const struct dentry *dentry) +{ + return dentry->d_count; +} + /* validate "insecure" dentry pointer */ extern int d_validate(struct dentry *, struct dentry *); diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index cb674d6d6ba2396297251617d6433798da2cfec5..e1a36370e3d7da449192810424830e574a4937a0 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -112,6 +112,7 @@ extern void __fd_install(struct files_struct *files, unsigned int fd, struct file *file); extern int __close_fd(struct files_struct *files, unsigned int fd); +extern int __close_fd_get_file(unsigned int fd, struct file **res); extern struct kmem_cache *files_cachep; diff --git a/include/linux/fs.h b/include/linux/fs.h index 49fe3a4cdb70d5e8f45cbc22c9736644502a7a2f..5bed10249a6ef7ba2e048dbe962c0460ed4b0bed 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -909,6 +909,7 @@ static inline int file_check_writeable(struct file *filp) #define FL_POSIX 1 #define FL_FLOCK 2 +#define FL_DELEG 4 /* NFSv4 delegation */ #define FL_ACCESS 8 /* not trying to lock, just looking */ #define FL_EXISTS 16 /* when unlocking, test for existence */ #define FL_LEASE 32 /* lease held on this file */ @@ -916,6 +917,7 @@ static inline int file_check_writeable(struct file *filp) #define FL_SLEEP 128 /* A blocking lock */ #define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ #define FL_UNLOCK_PENDING 512 /* Lease is being broken */ +#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ /* * Special return value from posix_lock_file() and vfs_lock_file() for @@ -930,7 +932,8 @@ static inline int file_check_writeable(struct file *filp) * * Lockd stuffs a "host" pointer into this. */ -typedef struct files_struct *fl_owner_t; +//typedef struct files_struct *fl_owner_t; +typedef void *fl_owner_t; struct file_lock_operations { void (*fl_copy_lock)(struct file_lock *, struct file_lock *); @@ -939,6 +942,9 @@ struct file_lock_operations { struct lock_manager_operations { int (*lm_compare_owner)(struct file_lock *, struct file_lock *); + unsigned long (*lm_owner_key)(struct file_lock *); + void (*lm_get_owner)(struct file_lock *, struct file_lock *); + void (*lm_put_owner)(struct file_lock *); void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, struct file_lock *, int); void (*lm_break)(struct file_lock *); @@ -957,14 +963,33 @@ int locks_in_grace(struct net *); /* that will die - we need it for nfs_lock_info */ #include +/* + * struct file_lock represents a generic "file lock". It's used to represent + * POSIX byte range locks, BSD (flock) locks, and leases. It's important to + * note that the same struct is used to represent both a request for a lock and + * the lock itself, but the same object is never used for both. + * + * FIXME: should we create a separate "struct lock_request" to help distinguish + * these two uses? + * + * The i_flock list is ordered by: + * + * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX + * 2) lock owner + * 3) lock range start + * 4) lock range end + * + * Obviously, the last two criteria only matter for POSIX locks. + */ struct file_lock { struct file_lock *fl_next; /* singly linked list for this inode */ - struct list_head fl_link; /* doubly linked list of all locks */ + struct hlist_node fl_link; /* node in global lists */ struct list_head fl_block; /* circular list of blocked processes */ fl_owner_t fl_owner; unsigned int fl_flags; unsigned char fl_type; unsigned int fl_pid; + int fl_link_cpu; /* what cpu's list is this on? */ struct pid *fl_nspid; wait_queue_head_t fl_wait; struct file *fl_file; @@ -1000,12 +1025,12 @@ struct file_lock { extern void send_sigio(struct fown_struct *fown, int fd, int band); #ifdef CONFIG_FILE_LOCKING -extern int fcntl_getlk(struct file *, struct flock __user *); +extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *); extern int fcntl_setlk(unsigned int, struct file *, unsigned int, struct flock __user *); #if BITS_PER_LONG == 32 -extern int fcntl_getlk64(struct file *, struct flock64 __user *); +extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 __user *); extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, struct flock64 __user *); #endif @@ -1018,30 +1043,26 @@ void locks_free_lock(struct file_lock *fl); extern void locks_init_lock(struct file_lock *); extern struct file_lock * locks_alloc_lock(void); extern void locks_copy_lock(struct file_lock *, struct file_lock *); -extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); +extern void locks_copy_conflock(struct file_lock *, struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); -extern void locks_remove_flock(struct file *); +extern void locks_remove_file(struct file *); extern void locks_release_private(struct file_lock *); extern void posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *); -extern int posix_unblock_lock(struct file *, struct file_lock *); +extern int posix_unblock_lock(struct file_lock *); extern int vfs_test_lock(struct file *, struct file_lock *); extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); -extern int __break_lease(struct inode *inode, unsigned int flags); +extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); extern void lease_get_mtime(struct inode *, struct timespec *time); extern int generic_setlease(struct file *, long, struct file_lock **); extern int vfs_setlease(struct file *, long, struct file_lock **); extern int lease_modify(struct file_lock **, int); -extern int lock_may_read(struct inode *, loff_t start, unsigned long count); -extern int lock_may_write(struct inode *, loff_t start, unsigned long count); -extern void locks_delete_block(struct file_lock *waiter); -extern void lock_flocks(void); -extern void unlock_flocks(void); #else /* !CONFIG_FILE_LOCKING */ -static inline int fcntl_getlk(struct file *file, struct flock __user *user) +static inline int fcntl_getlk(struct file *file, unsigned int cmd, + struct flock __user *user) { return -EINVAL; } @@ -1053,7 +1074,8 @@ static inline int fcntl_setlk(unsigned int fd, struct file *file, } #if BITS_PER_LONG == 32 -static inline int fcntl_getlk64(struct file *file, struct flock64 __user *user) +static inline int fcntl_getlk64(struct file *file, unsigned int cmd, + struct flock64 __user *user) { return -EINVAL; } @@ -1079,7 +1101,7 @@ static inline void locks_init_lock(struct file_lock *fl) return; } -static inline void __locks_copy_lock(struct file_lock *new, struct file_lock *fl) +static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) { return; } @@ -1094,7 +1116,7 @@ static inline void locks_remove_posix(struct file *filp, fl_owner_t owner) return; } -static inline void locks_remove_flock(struct file *filp) +static inline void locks_remove_file(struct file *filp) { return; } @@ -1115,8 +1137,7 @@ static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl) return -ENOLCK; } -static inline int posix_unblock_lock(struct file *filp, - struct file_lock *waiter) +static inline int posix_unblock_lock(struct file_lock *waiter) { return -ENOENT; } @@ -1143,7 +1164,7 @@ static inline int flock_lock_file_wait(struct file *filp, return -ENOLCK; } -static inline int __break_lease(struct inode *inode, unsigned int mode) +static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) { return 0; } @@ -1169,31 +1190,6 @@ static inline int lease_modify(struct file_lock **before, int arg) { return -EINVAL; } - -static inline int lock_may_read(struct inode *inode, loff_t start, - unsigned long len) -{ - return 1; -} - -static inline int lock_may_write(struct inode *inode, loff_t start, - unsigned long len) -{ - return 1; -} - -static inline void locks_delete_block(struct file_lock *waiter) -{ -} - -static inline void lock_flocks(void) -{ -} - -static inline void unlock_flocks(void) -{ -} - #endif /* !CONFIG_FILE_LOCKING */ @@ -1948,6 +1944,11 @@ extern bool our_mnt(struct vfsmount *mnt); extern int current_umask(void); +static inline struct inode *file_inode(struct file *f) +{ + return f->f_inode; +} + /* /sys/fs */ extern struct kobject *fs_kobj; @@ -1958,7 +1959,7 @@ extern int rw_verify_area(int, struct file *, loff_t *, size_t); #define FLOCK_VERIFY_WRITE 2 #ifdef CONFIG_FILE_LOCKING -extern int locks_mandatory_locked(struct inode *); +extern int locks_mandatory_locked(struct file *); extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t); /* @@ -1981,10 +1982,10 @@ static inline int mandatory_lock(struct inode *ino) return IS_MANDLOCK(ino) && __mandatory_lock(ino); } -static inline int locks_verify_locked(struct inode *inode) +static inline int locks_verify_locked(struct file *file) { - if (mandatory_lock(inode)) - return locks_mandatory_locked(inode); + if (mandatory_lock(file_inode(file))) + return locks_mandatory_locked(file); return 0; } @@ -2004,12 +2005,26 @@ static inline int locks_verify_truncate(struct inode *inode, static inline int break_lease(struct inode *inode, unsigned int mode) { + /* + * Since this check is lockless, we must ensure that any refcounts + * taken are done before checking inode->i_flock. Otherwise, we could + * end up racing with tasks trying to set a new lease on this file. + */ + smp_mb(); if (inode->i_flock) - return __break_lease(inode, mode); + return __break_lease(inode, mode, FL_LEASE); return 0; } + +static inline int break_deleg(struct inode *inode, unsigned int mode) +{ + if (inode->i_flock) + return __break_lease(inode, mode, FL_DELEG); + return 0; +} + #else /* !CONFIG_FILE_LOCKING */ -static inline int locks_mandatory_locked(struct inode *inode) +static inline int locks_mandatory_locked(struct file *file) { return 0; } @@ -2031,7 +2046,7 @@ static inline int mandatory_lock(struct inode *inode) return 0; } -static inline int locks_verify_locked(struct inode *inode) +static inline int locks_verify_locked(struct file *file) { return 0; } @@ -2047,6 +2062,10 @@ static inline int break_lease(struct inode *inode, unsigned int mode) return 0; } +static inline int break_deleg(struct inode *inode, unsigned int mode) +{ + return 0; +} #endif /* CONFIG_FILE_LOCKING */ /* fs/open.c */ @@ -2287,11 +2306,6 @@ static inline bool execute_ok(struct inode *inode) return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); } -static inline struct inode *file_inode(struct file *f) -{ - return f->f_inode; -} - static inline void file_start_write(struct file *file) { if (!S_ISREG(file_inode(file)->i_mode)) diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 35cd6c3307958c26a0d5bcc35874ab76039c112d..98ccdb469bb01cf7b60e79c709c512faea3c03d7 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -30,9 +31,109 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size) #include +/* + * Outside of CONFIG_HIGHMEM to support X86 32bit iomap_atomic() cruft. + */ +#ifdef CONFIG_KMAP_LOCAL +void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot); +void *__kmap_local_page_prot(struct page *page, pgprot_t prot); +void kunmap_local_indexed(void *vaddr); +#endif + #ifdef CONFIG_HIGHMEM #include +#ifndef ARCH_HAS_KMAP_FLUSH_TLB +static inline void kmap_flush_tlb(unsigned long addr) { } +#endif + +#ifndef kmap_prot +#define kmap_prot PAGE_KERNEL +#endif + +void *kmap_high(struct page *page); +static inline void *kmap(struct page *page) +{ + void *addr; + + might_sleep(); + if (!PageHighMem(page)) + addr = page_address(page); + else + addr = kmap_high(page); + kmap_flush_tlb((unsigned long)addr); + return addr; +} + +void kunmap_high(struct page *page); + +static inline void kunmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + +/* + * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because + * no global lock is needed and because the kmap code must perform a global TLB + * invalidation when the kmap pool wraps. + * + * However when holding an atomic kmap is is not legal to sleep, so atomic + * kmaps are appropriate for short, tight code paths only. + * + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap + * gives a more generic (and caching) interface. But kmap_atomic can + * be used in IRQ contexts, so in some (very limited) cases we need + * it. + */ + +#ifndef CONFIG_KMAP_LOCAL +void *kmap_atomic_high_prot(struct page *page, pgprot_t prot); +void kunmap_atomic_high(void *kvaddr); + +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + return kmap_atomic_high_prot(page, prot); +} + +static inline void __kunmap_atomic(void *vaddr) +{ + kunmap_atomic_high(vaddr); +} +#else /* !CONFIG_KMAP_LOCAL */ + +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) +{ + preempt_disable(); + pagefault_disable(); + return __kmap_local_page_prot(page, prot); +} + +static inline void *kmap_atomic_pfn(unsigned long pfn) +{ + preempt_disable(); + pagefault_disable(); + return __kmap_local_pfn_prot(pfn, kmap_prot); +} + +static inline void __kunmap_atomic(void *addr) +{ + kunmap_local_indexed(addr); +} + +#endif /* CONFIG_KMAP_LOCAL */ + +static inline void *kmap_atomic(struct page *page) +{ + return kmap_atomic_prot(page, kmap_prot); +} + /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); extern unsigned long totalhigh_pages; @@ -65,24 +166,41 @@ static inline void *kmap(struct page *page) return page_address(page); } +static inline void kunmap_high(struct page *page) +{ +} + static inline void kunmap(struct page *page) { } static inline void *kmap_atomic(struct page *page) { + preempt_disable(); pagefault_disable(); return page_address(page); } -#define kmap_atomic_prot(page, prot) kmap_atomic(page) -static inline void __kunmap_atomic(void *addr) +static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot) { - pagefault_enable(); + return kmap_atomic(page); } -#define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn)) -#define kmap_atomic_to_page(ptr) virt_to_page(ptr) +static inline void *kmap_atomic_pfn(unsigned long pfn) +{ + return kmap_atomic(pfn_to_page(pfn)); +} + +static inline void __kunmap_atomic(void *addr) +{ + /* + * Mostly nothing to do in the CONFIG_HIGHMEM=n case as kunmap_atomic() + * handles re-enabling faults and preemption + */ + #ifdef ARCH_HAS_FLUSH_ON_KUNMAP + kunmap_flush_on_unmap(addr); + #endif +} #define kmap_flush_unused() do {} while(0) #define kmap_atomic_flush_unused() do {} while (0) @@ -90,6 +208,7 @@ static inline void __kunmap_atomic(void *addr) #endif /* CONFIG_HIGHMEM */ +#if !defined(CONFIG_KMAP_LOCAL) #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) DECLARE_PER_CPU(int, __kmap_atomic_idx); @@ -100,7 +219,7 @@ static inline int kmap_atomic_idx_push(void) #ifdef CONFIG_DEBUG_HIGHMEM WARN_ON_ONCE(in_irq() && !irqs_disabled()); - BUG_ON(idx > KM_TYPE_NR); + BUG_ON(idx >= KM_TYPE_NR); #endif return idx; } @@ -120,20 +239,21 @@ static inline void kmap_atomic_idx_pop(void) __this_cpu_dec(__kmap_atomic_idx); #endif } - +#endif #endif /* * Prevent people trying to call kunmap_atomic() as if it were kunmap() * kunmap_atomic() should get the return value of kmap_atomic, not the page. */ -#define kunmap_atomic(addr) \ -do { \ - BUILD_BUG_ON(__same_type((addr), struct page *)); \ - __kunmap_atomic(addr); \ +#define kunmap_atomic(__addr) \ +do { \ + BUILD_BUG_ON(__same_type((__addr), struct page *)); \ + __kunmap_atomic(__addr); \ + pagefault_enable(); \ + preempt_enable(); \ } while (0) - /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ #ifndef clear_user_highpage static inline void clear_user_highpage(struct page *page, unsigned long vaddr) @@ -211,6 +331,27 @@ static inline void clear_highpage(struct page *page) kunmap_atomic(kaddr); } +static inline void sanitize_highpage(struct page *page) +{ + void *kaddr; + unsigned long flags; + + local_irq_save(flags); + kaddr = kmap_atomic(page); + clear_page(kaddr); + kunmap_atomic(kaddr); + local_irq_restore(flags); +} + +static inline void sanitize_highpage_verify(struct page *page) +{ + void *kaddr; + + kaddr = kmap_atomic(page); + BUG_ON(memchr_inv(kaddr, 0, PAGE_SIZE)); + kunmap_atomic(kaddr); +} + static inline void zero_user_segments(struct page *page, unsigned start1, unsigned end1, unsigned start2, unsigned end2) @@ -257,6 +398,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from, #endif +#ifndef __HAVE_ARCH_COPY_HIGHPAGE + static inline void copy_highpage(struct page *to, struct page *from) { char *vfrom, *vto; @@ -268,4 +411,6 @@ static inline void copy_highpage(struct page *to, struct page *from) kunmap_atomic(vfrom); } +#endif + #endif /* _LINUX_HIGHMEM_H */ diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h index 657fab4efab351070a9aaf7a625759159a786580..c27dde7215b5b291394747d35e1f4a19d9f1ac8e 100644 --- a/include/linux/io-mapping.h +++ b/include/linux/io-mapping.h @@ -141,6 +141,7 @@ static inline void __iomem * io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset) { + preempt_disable(); pagefault_disable(); return ((char __force __iomem *) mapping) + offset; } @@ -149,6 +150,7 @@ static inline void io_mapping_unmap_atomic(void __iomem *vaddr) { pagefault_enable(); + preempt_enable(); } /* Non-atomic map/unmap */ diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h new file mode 100644 index 0000000000000000000000000000000000000000..2fe13e1a809aab48c4948031a6f4e5680fe85df7 --- /dev/null +++ b/include/linux/list_lru.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved. + * Authors: David Chinner and Glauber Costa + * + * Generic LRU infrastructure + */ +#ifndef _LRU_LIST_H +#define _LRU_LIST_H + +#include +#include + +/* list_lru_walk_cb has to always return one of those */ +enum lru_status { + LRU_REMOVED, /* item removed from list */ + LRU_ROTATE, /* item referenced, give another pass */ + LRU_SKIP, /* item cannot be locked, skip */ + LRU_RETRY, /* item not freeable. May drop the lock + internally, but has to return locked. */ +}; + +struct list_lru_node { + spinlock_t lock; + struct list_head list; + /* kept as signed so we can catch imbalance bugs */ + long nr_items; +} ____cacheline_aligned_in_smp; + +struct list_lru { + /* + * Because we use a fixed-size array, this struct can be very big if + * MAX_NUMNODES is big. If this becomes a problem this is fixable by + * turning this into a pointer and dynamically allocating this to + * nr_node_ids. This quantity is firwmare-provided, and still would + * provide room for all nodes at the cost of a pointer lookup and an + * extra allocation. Because that allocation will most likely come from + * a different slab cache than the main structure holding this + * structure, we may very well fail. + */ + struct list_lru_node node[MAX_NUMNODES]; + nodemask_t active_nodes; +}; + +int list_lru_init(struct list_lru *lru); + +/** + * list_lru_add: add an element to the lru list's tail + * @list_lru: the lru pointer + * @item: the item to be added. + * + * If the element is already part of a list, this function returns doing + * nothing. Therefore the caller does not need to keep state about whether or + * not the element already belongs in the list and is allowed to lazy update + * it. Note however that this is valid for *a* list, not *this* list. If + * the caller organize itself in a way that elements can be in more than + * one type of list, it is up to the caller to fully remove the item from + * the previous list (with list_lru_del() for instance) before moving it + * to @list_lru + * + * Return value: true if the list was updated, false otherwise + */ +bool list_lru_add(struct list_lru *lru, struct list_head *item); + +/** + * list_lru_del: delete an element to the lru list + * @list_lru: the lru pointer + * @item: the item to be deleted. + * + * This function works analogously as list_lru_add in terms of list + * manipulation. The comments about an element already pertaining to + * a list are also valid for list_lru_del. + * + * Return value: true if the list was updated, false otherwise + */ +bool list_lru_del(struct list_lru *lru, struct list_head *item); + +/** + * list_lru_count_node: return the number of objects currently held by @lru + * @lru: the lru pointer. + * @nid: the node id to count from. + * + * Always return a non-negative number, 0 for empty lists. There is no + * guarantee that the list is not updated while the count is being computed. + * Callers that want such a guarantee need to provide an outer lock. + */ +unsigned long list_lru_count_node(struct list_lru *lru, int nid); +static inline unsigned long list_lru_count(struct list_lru *lru) +{ + long count = 0; + int nid; + + for_each_node_mask(nid, lru->active_nodes) + count += list_lru_count_node(lru, nid); + + return count; +} + +typedef enum lru_status +(*list_lru_walk_cb)(struct list_head *item, spinlock_t *lock, void *cb_arg); +/** + * list_lru_walk_node: walk a list_lru, isolating and disposing freeable items. + * @lru: the lru pointer. + * @nid: the node id to scan from. + * @isolate: callback function that is resposible for deciding what to do with + * the item currently being scanned + * @cb_arg: opaque type that will be passed to @isolate + * @nr_to_walk: how many items to scan. + * + * This function will scan all elements in a particular list_lru, calling the + * @isolate callback for each of those items, along with the current list + * spinlock and a caller-provided opaque. The @isolate callback can choose to + * drop the lock internally, but *must* return with the lock held. The callback + * will return an enum lru_status telling the list_lru infrastructure what to + * do with the object being scanned. + * + * Please note that nr_to_walk does not mean how many objects will be freed, + * just how many objects will be scanned. + * + * Return value: the number of objects effectively removed from the LRU. + */ +unsigned long list_lru_walk_node(struct list_lru *lru, int nid, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long *nr_to_walk); + +static inline unsigned long +list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, + void *cb_arg, unsigned long nr_to_walk) +{ + long isolated = 0; + int nid; + + for_each_node_mask(nid, lru->active_nodes) { + isolated += list_lru_walk_node(lru, nid, isolate, + cb_arg, &nr_to_walk); + if (nr_to_walk <= 0) + break; + } + return isolated; +} + +typedef void (*list_lru_dispose_cb)(struct list_head *dispose_list); +/** + * list_lru_dispose_all: forceably flush all elements in an @lru + * @lru: the lru pointer + * @dispose: callback function to be called for each lru list. + * + * This function will forceably isolate all elements into the dispose list, and + * call the @dispose callback to flush the list. Please note that the callback + * should expect items in any state, clean or dirty, and be able to flush all of + * them. + * + * Return value: how many objects were freed. It should be equal to all objects + * in the list_lru. + */ +unsigned long +list_lru_dispose_all(struct list_lru *lru, list_lru_dispose_cb dispose); +#endif /* _LRU_LIST_H */ diff --git a/include/linux/module.h b/include/linux/module.h index 761dc2848ffafb003f9c62245ad1c7908e1f2d7f..2aef36fc43a602d19f3f3ea99fc58ae53e545223 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -136,8 +136,8 @@ extern const struct gtype##_id __mod_##gtype##_table \ /* What your module does. */ #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) -#define MODULE_DEVICE_TABLE(type,name) \ - MODULE_GENERIC_TABLE(type##_device,name) +#define MODULE_DEVICE_TABLE(type, name) \ + MODULE_GENERIC_TABLE(type##__##name##_device, name) /* Version of form [:][-]. Or for CVS/RCS ID version, everything but the number is stripped. diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h index cee918c843028ceb651c068d245efe02b9113601..5fed69b01772a5d3c28868d365194d3a50da749e 100644 --- a/include/linux/msm_thermal.h +++ b/include/linux/msm_thermal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, The Linux Foundation. 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 and @@ -90,6 +90,7 @@ struct therm_threshold { int32_t trip_triggered; void (*notify)(struct therm_threshold *); struct threshold_info *parent; + int32_t cur_state; }; struct threshold_info { diff --git a/include/linux/net.h b/include/linux/net.h index 65545ac6fb9cfebd04040e6371eae6233b6b5f64..e55ae4872891ee19d02338403a7736a81afedbbd 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -24,6 +24,7 @@ #include /* For O_CLOEXEC and O_NONBLOCK */ #include #include +#include #include struct poll_table_struct; @@ -251,6 +252,23 @@ do { \ #define net_random() prandom_u32() #define net_srandom(seed) prandom_seed((__force u32)(seed)) +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *done_key); + +#define net_get_random_once(buf, nbytes) \ + ({ \ + bool ___ret = false; \ + static bool ___done = false; \ + static struct static_key ___once_key = \ + STATIC_KEY_INIT_TRUE; \ + if (static_key_true(&___once_key)) \ + ___ret = __net_get_random_once(buf, \ + nbytes, \ + &___done, \ + &___once_key); \ + ___ret; \ + }) + extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t len); extern int kernel_recvmsg(struct socket *sock, struct msghdr *msg, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fddc4bf17d4adc9f8f47e5fdb4994cd6027bdadb..ed3778f37a14b951ca441e953a1bee6749f9e914 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2599,6 +2599,8 @@ extern void ether_setup(struct net_device *dev); extern struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int txqs, unsigned int rxqs); +extern int dev_get_valid_name(struct net *net, struct net_device *dev, + const char *name); #define alloc_netdev(sizeof_priv, name, setup) \ alloc_netdev_mqs(sizeof_priv, name, setup, 1, 1) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 547a5846e6ac4b3ce1692ec75f3357e0d7782842..8127e7bca2ffa0ce6beea5468309b4d510ea7197 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -248,6 +248,8 @@ extern int xt_check_match(struct xt_mtchk_param *, extern int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); +extern int xt_check_proc_name(const char *name, unsigned int size); + void *xt_copy_counters_from_user(const void __user *user, unsigned int len, struct xt_counters_info *info, bool compat); diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 73786fb03e1bf5272288e3e7135ceea03b60c396..c66ef503cf47e1bea3d09d27dbf32997852b07d9 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -98,6 +98,23 @@ typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t; extern nodemask_t _unused_nodemask_arg_; +/** + * nodemask_pr_args - printf args to output a nodemask + * @maskp: nodemask to be printed + * + * Can be used to provide arguments for '%*pb[l]' when printing a nodemask. + */ +#define nodemask_pr_args(maskp) MAX_NUMNODES, (maskp)->bits + +/* + * The inline keyword gives the compiler room to decide to inline, or + * not inline a function as it sees best. However, as these functions + * are called in both __init and non-__init functions, if they are not + * inlined we will end up with a section mis-match error (of the type of + * freeable items not being freed). So we must use __always_inline here + * to fix the problem. If other functions in the future also end up in + * this situation they will also need to be annotated as __always_inline + */ #define node_set(node, dst) __node_set((node), &(dst)) static inline void __node_set(int node, volatile nodemask_t *dstp) { diff --git a/include/linux/partialresume.h b/include/linux/partialresume.h new file mode 100644 index 0000000000000000000000000000000000000000..69dfa0bc0009702b3cb67ccbf76ff95555ec9883 --- /dev/null +++ b/include/linux/partialresume.h @@ -0,0 +1,54 @@ +/* include/linux/partialresume.h + * + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_PARTIALRESUME_H +#define _LINUX_PARTIALRESUME_H + +#ifdef CONFIG_PARTIALRESUME + +#include + +struct partial_resume_stats { + unsigned total; + unsigned total_yes; +}; + +struct partial_resume { + struct list_head next_handler; + struct list_head next_match; + int irq; + struct partial_resume_stats stats; + bool (*partial_resume)(struct partial_resume *); +}; + +int register_partial_resume(struct partial_resume *handler); +void unregister_partial_resume(struct partial_resume *handler); + +bool suspend_again_match(const struct list_head *irqs, + const struct list_head *unfinished); +bool suspend_again_consensus(void); + +#else /* !CONFIG_PARTIALRESUME */ + +struct partial_resume; +static inline int register_partial_resume(struct partial_resume *handler) { return 0; } +static inline void unregister_partial_resume(struct partial_resume *handler) {} +static inline bool suspend_again_match(const struct list_head *irqs, size_t irqs_len) { return false; } +static inline bool suspend_again_consensus(void) { return false; } + +#endif + +#endif + diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 8fa2eea87f6a450791dedd71a45c48ae22745ffb..5d2ad5cb800a12e7c7a1d8289b41b16cd2b038f4 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -196,6 +196,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_FV_CFG, POWER_SUPPLY_PROP_FV_CMP_CFG, POWER_SUPPLY_PROP_BATT_AGING, + POWER_SUPPLY_PROP_SOC_REPORTING_READY, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ diff --git a/include/linux/refcount.h b/include/linux/refcount.h new file mode 100644 index 0000000000000000000000000000000000000000..9c63f5bcd91d293eae8e1a7017f2211e5a8ed24d --- /dev/null +++ b/include/linux/refcount.h @@ -0,0 +1,127 @@ +#ifndef _LINUX_REFCOUNT_H +#define _LINUX_REFCOUNT_H + +#include +#include +#include +#include + +struct mutex; + +/** + * refcount_t - variant of atomic_t specialized for reference counts + * @refs: atomic_t counter field + * + * The counter saturates at REFCOUNT_SATURATED and will not move once + * there. This avoids wrapping the counter and causing 'spurious' + * use-after-free bugs. + */ +typedef struct refcount_struct { + atomic_t refs; +} refcount_t; + +#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), } + +/** + * refcount_set - set a refcount's value + * @r: the refcount + * @n: value to which the refcount will be set + */ +static inline void refcount_set(refcount_t *r, int n) +{ + atomic_set(&r->refs, n); +} + +/** + * refcount_read - get a refcount's value + * @r: the refcount + * + * Return: the refcount's value + */ +static inline unsigned int refcount_read(const refcount_t *r) +{ + return atomic_read(&r->refs); +} + +#ifdef CONFIG_REFCOUNT_FULL + +#define REFCOUNT_MAX (UINT_MAX - 1) +#define REFCOUNT_SATURATED UINT_MAX + +extern __must_check bool refcount_add_not_zero(int i, refcount_t *r); +extern void refcount_add(int i, refcount_t *r); + +extern __must_check bool refcount_inc_not_zero(refcount_t *r); +extern void refcount_inc(refcount_t *r); + +extern __must_check bool refcount_sub_and_test(int i, refcount_t *r); + +extern void refcount_sub(unsigned int i, refcount_t *r); + +extern __must_check bool refcount_inc_not_zero(refcount_t *r); +extern void refcount_inc(refcount_t *r); + +extern __must_check bool refcount_sub_and_test(int i, refcount_t *r); + +extern __must_check bool refcount_dec_and_test(refcount_t *r); +extern void refcount_dec(refcount_t *r); + +#else + + +#define REFCOUNT_MAX INT_MAX +#define REFCOUNT_SATURATED (INT_MIN / 2) + +# ifdef CONFIG_ARCH_HAS_REFCOUNT +# include +# else +static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r) +{ + return atomic_add_unless(&r->refs, i, 0); +} + +static inline void refcount_add(int i, refcount_t *r) +{ + atomic_add(i, &r->refs); +} + +static inline __must_check bool refcount_inc_not_zero(refcount_t *r) +{ + return atomic_add_unless(&r->refs, 1, 0); +} + +static inline void refcount_inc(refcount_t *r) +{ + atomic_inc(&r->refs); +} + +static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r) +{ + return atomic_sub_and_test(i, &r->refs); +} + +static inline void refcount_sub(unsigned int i, refcount_t *r) +{ + atomic_sub(i, &r->refs); +} + +static inline __must_check bool refcount_dec_and_test(refcount_t *r) +{ + return atomic_dec_and_test(&r->refs); +} + +static inline void refcount_dec(refcount_t *r) +{ + atomic_dec(&r->refs); +} +# endif /* !CONFIG_ARCH_HAS_REFCOUNT */ +#endif /* CONFIG_REFCOUNT_FULL */ + +extern __must_check bool refcount_dec_if_one(refcount_t *r); +extern __must_check bool refcount_dec_not_one(refcount_t *r); +extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock); +extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock); +extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r, + spinlock_t *lock, + unsigned long *flags); +#endif /* _LINUX_REFCOUNT_H */ diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 6fda30530e9bb78f91141ae074b13f9fb13906f0..692e03a84bcf70d8617f200da4e1d4adb4f08121 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -37,6 +37,21 @@ struct seq_operations { #define SEQ_SKIP 1 +/** + * seq_has_overflowed - check if the buffer has overflowed + * @m: the seq_file handle + * + * seq_files have a buffer which may overflow. When this happens a larger + * buffer is reallocated and all the data will be printed again. + * The overflow state is true when m->count == m->size. + * + * Returns true if the buffer received more than it can hold. + */ +static inline bool seq_has_overflowed(struct seq_file *m) +{ + return m->count == m->size; +} + /** * seq_get_buf - get buffer to write arbitrary data to * @m: the seq_file handle @@ -143,6 +158,20 @@ int seq_put_decimal_ull(struct seq_file *m, char delimiter, int seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num); +#define DEFINE_SHOW_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __name ## _show, inode->i_private); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + static inline struct user_namespace *seq_user_ns(struct seq_file *seq) { #ifdef CONFIG_USER_NS @@ -183,4 +212,10 @@ extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, extern struct hlist_node *seq_hlist_next_rcu(void *v, struct hlist_head *head, loff_t *ppos); + +/* Helpers for iterating over per-cpu hlist_head-s in seq_files */ +extern struct hlist_node *seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos); + +extern struct hlist_node *seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, int *cpu, loff_t *pos); + #endif diff --git a/include/linux/slab.h b/include/linux/slab.h index 0c621752caa66d67a26c7ba1089fc71faa6b0d32..0756780e34011d3b37eec577c8721d675c00bf94 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -133,6 +133,18 @@ void kfree(const void *); void kzfree(const void *); size_t ksize(const void *); +#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR +const char *__check_heap_object(const void *ptr, unsigned long n, + struct page *page); +#else +static inline const char *__check_heap_object(const void *ptr, + unsigned long n, + struct page *page) +{ + return NULL; +} +#endif + /* * Some archs want to perform DMA into kmalloc caches and need a guaranteed * alignment larger than the alignment of a 64-bit integer. diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 027276fa87132728d2c914ccc38fc09bc7602395..6899e84124364ad69f1ea2500d10163b4fc9dd87 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -85,6 +85,7 @@ struct kmem_cache { int inuse; /* Offset to metadata */ int align; /* Alignment */ int reserved; /* Reserved bytes at the end of slabs */ + int red_left_pad; /* Left redzone padding size */ const char *name; /* Name (only for display!) */ struct list_head list; /* List of slab caches */ #ifdef CONFIG_SYSFS @@ -95,6 +96,10 @@ struct kmem_cache { int max_attr_size; /* for propagation, maximum size of a stored attr */ #endif + unsigned long random; + unsigned long random_active; + unsigned long random_inactive; + #ifdef CONFIG_NUMA /* * Defragmentation by allocating from a remote node. diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 4ae6f32c8033de9ae577ef2e8418a2ba36a65b7f..b9b269dbf693ec8499da364c41746fbff7e1c23a 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -51,6 +51,18 @@ struct restart_block { extern long do_no_restart_syscall(struct restart_block *parm); #include + +/* + * For per-arch arch_within_stack_frames() implementations, defined in + * asm/thread_info.h. + */ +enum { + BAD_STACK = -1, + NOT_STACK = 0, + GOOD_FRAME, + GOOD_STACK, +}; + #include #ifdef __KERNEL__ @@ -150,6 +162,30 @@ static inline bool test_and_clear_restore_sigmask(void) #error "no set_restore_sigmask() provided and default one won't work" #endif +#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES +static inline int arch_within_stack_frames(const void * const stack, + const void * const stackend, + const void *obj, unsigned long len) +{ + return 0; +} +#endif + +#ifdef CONFIG_HARDENED_USERCOPY +extern void __check_object_size(const void *ptr, unsigned long n, + bool to_user); + +static inline void check_object_size(const void *ptr, unsigned long n, + bool to_user) +{ + __check_object_size(ptr, n, to_user); +} +#else +static inline void check_object_size(const void *ptr, unsigned long n, + bool to_user) +{ } +#endif /* CONFIG_HARDENED_USERCOPY */ + #endif /* __KERNEL__ */ #endif /* _LINUX_THREAD_INFO_H */ diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index b2df2b81a2f32ce740fa37fe08b71873507beb2d..a6b09f9bc46e056aa206422a8c555c36aee53eb4 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -34,12 +34,15 @@ struct usbnet { struct mutex phy_mutex; unsigned char suspend_count; unsigned char pkt_cnt, pkt_err; + unsigned short rx_qlen, tx_qlen; + unsigned can_dma_sg:1; /* i/o info: pipes etc */ unsigned in, out; struct usb_host_endpoint *status; unsigned maxpacket; struct timer_list delay; + const char *padding_pkt; /* protocol/interface state */ struct net_device *net; @@ -75,6 +78,7 @@ struct usbnet { # define EVENT_NO_RUNTIME_PM 9 # define EVENT_RX_KILL 10 # define EVENT_LINK_CHANGE 11 +# define EVENT_SET_RX_MODE 12 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) @@ -153,6 +157,9 @@ struct driver_info { /* called by minidriver when receiving indication */ void (*indication)(struct usbnet *dev, void *ind, int indlen); + /* rx mode change (device changes address list filtering) */ + void (*set_rx_mode)(struct usbnet *dev); + /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ int out; /* tx endpoint */ @@ -254,4 +261,6 @@ extern void usbnet_link_change(struct usbnet *, bool, bool); extern int usbnet_status_start(struct usbnet *dev, gfp_t mem_flags); extern void usbnet_status_stop(struct usbnet *dev); +extern void usbnet_update_max_qlen(struct usbnet *dev); + #endif /* __LINUX_USB_USBNET_H */ diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index b88fb02066e87911ca2caa8eddaecb1d61328836..e4c0b5686b342a4e2cb0c5312ca753aa00fedc01 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -15,6 +15,7 @@ #define _WCNSS_WLAN_H_ #include +#include enum wcnss_opcode { WCNSS_WLAN_SWITCH_OFF = 0, @@ -30,7 +31,11 @@ struct wcnss_wlan_config { int use_48mhz_xo; int is_pronto_vt; int is_pronto_v3; + int is_pronto_v4; void __iomem *msm_wcnss_base; + int iris_id; + int vbatt; + int pc_disable_latency; }; enum { @@ -48,10 +53,16 @@ enum { WCNSS_WLAN_MAX_GPIO, }; +#define WCNSS_VBATT_THRESHOLD 3500000 +#define WCNSS_VBATT_GUARD 20000 +#define WCNSS_VBATT_HIGH 3700000 +#define WCNSS_VBATT_LOW 3300000 +#define WCNSS_VBATT_INITIAL 3000000 #define WCNSS_WLAN_IRQ_INVALID -1 #define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1 #define HAVE_WCNSS_RESET_INTR 1 #define HAVE_WCNSS_CAL_DOWNLOAD 1 +#define HAVE_CBC_DONE 1 #define HAVE_WCNSS_RX_BUFF_COUNT 1 #define WLAN_MAC_ADDR_SIZE (6) #define WLAN_RF_REG_ADDR_START_OFFSET 0x3 @@ -98,18 +109,27 @@ void wcnss_prevent_suspend(void); int wcnss_hardware_type(void); void *wcnss_prealloc_get(unsigned int size); int wcnss_prealloc_put(void *ptr); -void wcnss_reset_intr(void); +void wcnss_reset_fiq(bool clk_chk_en); void wcnss_suspend_notify(void); void wcnss_resume_notify(void); void wcnss_riva_log_debug_regs(void); void wcnss_pronto_log_debug_regs(void); int wcnss_is_hw_pronto_ver3(void); int wcnss_device_ready(void); +bool wcnss_cbc_complete(void); int wcnss_device_is_shutdown(void); void wcnss_riva_dump_pmic_regs(void); int wcnss_xo_auto_detect_enabled(void); u32 wcnss_get_wlan_rx_buff_count(void); int wcnss_wlan_iris_xo_mode(void); +void wcnss_flush_work(struct work_struct *work); +void wcnss_flush_delayed_work(struct delayed_work *dwork); +void wcnss_init_work(struct work_struct *work , void *callbackptr); +void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr); +int wcnss_get_iris_name(char *iris_version); +void wcnss_en_wlan_led_trigger(void); +void wcnss_dump_stack(struct task_struct *task); + #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); #else diff --git a/include/net/Space.h b/include/net/Space.h new file mode 100644 index 0000000000000000000000000000000000000000..8a32771e4215f337f29e492baecafa4eb42c69ee --- /dev/null +++ b/include/net/Space.h @@ -0,0 +1,31 @@ +/* A unified ethernet device probe. This is the easiest way to have every + * ethernet adaptor have the name "eth[0123...]". + */ + +struct net_device *hp100_probe(int unit); +struct net_device *ultra_probe(int unit); +struct net_device *wd_probe(int unit); +struct net_device *ne_probe(int unit); +struct net_device *fmv18x_probe(int unit); +struct net_device *i82596_probe(int unit); +struct net_device *ni65_probe(int unit); +struct net_device *sonic_probe(int unit); +struct net_device *smc_init(int unit); +struct net_device *atarilance_probe(int unit); +struct net_device *sun3lance_probe(int unit); +struct net_device *sun3_82586_probe(int unit); +struct net_device *apne_probe(int unit); +struct net_device *cs89x0_probe(int unit); +struct net_device *mvme147lance_probe(int unit); +struct net_device *tc515_probe(int unit); +struct net_device *lance_probe(int unit); +struct net_device *mac8390_probe(int unit); +struct net_device *mac89x0_probe(int unit); +struct net_device *cops_probe(int unit); +struct net_device *ltpc_probe(void); + +/* Fibre Channel adapters */ +int iph5526_probe(struct net_device *dev); + +/* SBNI adapters */ +int sbni_probe(int unit); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e3241dedc1c0f1e72bc4eeba03ecbfb0279360b6..daac3ecc1fe0c0d69c8e63b5765ddbaf05331ffc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -63,6 +63,8 @@ struct wiphy; #define TDLS_MGMT_VERSION2 1 #define CFG80211_BSSID_HINT_BACKPORT 1 +#define CFG80211_DEL_STA_V2 1 + /* * wireless hardware capability structures */ @@ -699,6 +701,22 @@ struct station_parameters { u8 supported_oper_classes_len; }; +/** + * struct station_del_parameters - station deletion parameters + * + * Used to delete a station entry (or all stations). + * + * @mac: MAC address of the station to remove or NULL to remove all stations + * @subtype: Management frame subtype to use for indicating removal + * (10 = Disassociation, 12 = Deauthentication) + * @reason_code: Reason code for the Disassociation/Deauthentication frame + */ +struct station_del_parameters { + const u8 *mac; + u8 subtype; + u16 reason_code; +}; + /** * enum cfg80211_station_type - the type of station being modified * @CFG80211_STA_AP_CLIENT: client of an AP interface @@ -1915,7 +1933,7 @@ struct cfg80211_qos_map { * @stop_ap: Stop being an AP, including stopping beaconing. * * @add_station: Add a new station. - * @del_station: Remove a station; @mac may be NULL to remove all stations. + * @del_station: Remove a station * @change_station: Modify a given station. Note that flags changes are not much * validated in cfg80211, in particular the auth/assoc/authorized flags * might come to the driver in invalid combinations -- make sure to check @@ -2140,7 +2158,7 @@ struct cfg80211_ops { int (*add_station)(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); int (*del_station)(struct wiphy *wiphy, struct net_device *dev, - u8 *mac); + struct station_del_parameters *params); int (*change_station)(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params); int (*get_station)(struct wiphy *wiphy, struct net_device *dev, diff --git a/include/net/dst.h b/include/net/dst.h index e0c97f5a57cfca46af67a2d793349279f146f546..07ac25afb4e19f7825613ccb75343ded30009488 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -306,6 +306,39 @@ static inline void skb_dst_force(struct sk_buff *skb) } } +/** + * dst_hold_safe - Take a reference on a dst if possible + * @dst: pointer to dst entry + * + * This helper returns false if it could not safely + * take a reference on a dst. + */ +static inline bool dst_hold_safe(struct dst_entry *dst) +{ + if (dst->flags & DST_NOCACHE) + return atomic_inc_not_zero(&dst->__refcnt); + dst_hold(dst); + return true; +} + +/** + * skb_dst_force_safe - makes sure skb dst is refcounted + * @skb: buffer + * + * If dst is not yet refcounted and not destroyed, grab a ref on it. + */ +static inline void skb_dst_force_safe(struct sk_buff *skb) +{ + if (skb_dst_is_noref(skb)) { + struct dst_entry *dst = skb_dst(skb); + + if (!dst_hold_safe(dst)) + dst = NULL; + + skb->_skb_refdst = (unsigned long)dst; + } +} + /** * __skb_tunnel_rx - prepare skb for rx reinsert diff --git a/include/net/flow.h b/include/net/flow.h index 1964eeb57a325f740e85959568aa9bb83db74860..15ecdd07e19263dee26b7fcfe1d49b6d9628a3eb 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -89,7 +89,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, __u32 mark, __u8 tos, __u8 scope, __u8 proto, __u8 flags, __be32 daddr, __be32 saddr, - __be16 dport, __be16 sport) + __be16 dport, __be16 sport, + kuid_t uid) { fl4->flowi4_oif = oif; fl4->flowi4_iif = LOOPBACK_IFINDEX; @@ -99,6 +100,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->flowi4_proto = proto; fl4->flowi4_flags = flags; fl4->flowi4_secid = 0; + fl4->flowi4_uid = uid; fl4->daddr = daddr; fl4->saddr = saddr; fl4->fl4_dport = dport; diff --git a/include/net/ip.h b/include/net/ip.h index 5bb62242de0ee99e637f044cd5a8691be2a1d3f4..6922e1ea084aff92471469fa31609aa0de55512c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -31,6 +31,8 @@ #include #include +#define IPV4_MIN_MTU 68 /* RFC 791 */ + struct sock; struct inet_skb_parm { @@ -155,6 +157,7 @@ struct ip_reply_arg { /* -1 if not needed */ int bound_dev_if; u8 tos; + kuid_t uid; }; #define IP_REPLY_ARG_NOSRCCHECK 1 diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 8d977b3436474b057bd29d3898bfa771e14c23fb..30f068fafaadb51f72cae7e48f2db1d0c7d23902 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -136,10 +136,11 @@ extern int rt6_route_rcv(struct net_device *dev, const struct in6_addr *gwaddr); extern void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, - int oif, u32 mark); + int oif, u32 mark, kuid_t uid); extern void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu); -extern void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark); +extern void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, + kuid_t uid); extern void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk); struct netlink_callback; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 1c581b99c64b4a80dad56177deea701850ac56af..931f09d94b8e6539c58a798e460f9ece1b1d8c22 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -682,6 +682,8 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } +void ipv6_proxy_select_ident(struct sk_buff *skb); + /* * Header manipulation */ diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index b064d6dd14fba44ef4c8d48bc911bb231a671368..350ea246a940c6fb1cca1c0b3bf3d5786924c6ce 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -181,6 +181,11 @@ int net_eq(const struct net *net1, const struct net *net2) return net1 == net2; } +static inline int check_net(const struct net *net) +{ + return atomic_read(&net->count) != 0; +} + extern void net_drop_ns(void *); #else @@ -205,6 +210,11 @@ int net_eq(const struct net *net1, const struct net *net2) return 1; } +static inline int check_net(const struct net *net) +{ + return 1; +} + #define net_drop_ns NULL #endif diff --git a/include/net/route.h b/include/net/route.h index 2ea40c1b5e009746dacb8f146fdcc37309aa7ff3..4fe676279a475ae6e142b43bd007e8faa21b69e5 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -142,7 +142,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, RT_SCOPE_UNIVERSE, proto, sk ? inet_sk_flowi_flags(sk) : 0, - daddr, saddr, dport, sport); + daddr, saddr, dport, sport, sock_net_uid(net, sk)); if (sk) security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); return ip_route_output_flow(net, fl4, sk); @@ -253,7 +253,8 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 flow_flags |= FLOWI_FLAG_CAN_SLEEP; flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - protocol, flow_flags, dst, src, dport, sport); + protocol, flow_flags, dst, src, dport, sport, + sk->sk_uid); } static inline struct rtable *ip_route_connect(struct flowi4 *fl4, diff --git a/include/net/sock.h b/include/net/sock.h index c8f589152cfdf41ce32d28cefcc7d984960da3fd..3d4b98d54edbcbd6a4888aa561d75264ac444eff 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -758,7 +758,7 @@ static inline bool sk_stream_memory_free(const struct sock *sk) static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) { /* dont let skb dst not refcounted, we are going to leave rcu lock */ - skb_dst_force(skb); + skb_dst_force_safe(skb); if (!sk->sk_backlog.tail) sk->sk_backlog.head = skb; @@ -812,30 +812,44 @@ static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) return sk->sk_backlog_rcv(sk, skb); } -static inline void sock_rps_record_flow(const struct sock *sk) +static inline void sock_rps_record_flow_hash(__u32 hash) { #ifdef CONFIG_RPS struct rps_sock_flow_table *sock_flow_table; rcu_read_lock(); sock_flow_table = rcu_dereference(rps_sock_flow_table); - rps_record_sock_flow(sock_flow_table, sk->sk_rxhash); + rps_record_sock_flow(sock_flow_table, hash); rcu_read_unlock(); #endif } -static inline void sock_rps_reset_flow(const struct sock *sk) +static inline void sock_rps_reset_flow_hash(__u32 hash) { #ifdef CONFIG_RPS struct rps_sock_flow_table *sock_flow_table; rcu_read_lock(); sock_flow_table = rcu_dereference(rps_sock_flow_table); - rps_reset_sock_flow(sock_flow_table, sk->sk_rxhash); + rps_reset_sock_flow(sock_flow_table, hash); rcu_read_unlock(); #endif } +static inline void sock_rps_record_flow(const struct sock *sk) +{ +#ifdef CONFIG_RPS + sock_rps_record_flow_hash(sk->sk_rxhash); +#endif +} + +static inline void sock_rps_reset_flow(const struct sock *sk) +{ +#ifdef CONFIG_RPS + sock_rps_reset_flow_hash(sk->sk_rxhash); +#endif +} + static inline void sock_rps_save_rxhash(struct sock *sk, const struct sk_buff *skb) { @@ -875,7 +889,7 @@ extern void sk_stream_kill_queues(struct sock *sk); extern void sk_set_memalloc(struct sock *sk); extern void sk_clear_memalloc(struct sock *sk); -extern int sk_wait_data(struct sock *sk, long *timeo); +int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb); struct request_sock_ops; struct timewait_sock_ops; @@ -2293,6 +2307,8 @@ bool sk_ns_capable(const struct sock *sk, struct user_namespace *user_ns, int cap); bool sk_capable(const struct sock *sk, int cap); bool sk_net_capable(const struct sock *sk, int cap); +extern int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, + int level, int type); /* * Enable debug/info messages diff --git a/include/trace/events/filelock.h b/include/trace/events/filelock.h new file mode 100644 index 0000000000000000000000000000000000000000..59d11c22f07639ca586a46644ef32b6e061b4ce1 --- /dev/null +++ b/include/trace/events/filelock.h @@ -0,0 +1,96 @@ +/* + * Events for filesystem locks + * + * Copyright 2013 Jeff Layton + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM filelock + +#if !defined(_TRACE_FILELOCK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FILELOCK_H + +#include +#include +#include +#include + +#define show_fl_flags(val) \ + __print_flags(val, "|", \ + { FL_POSIX, "FL_POSIX" }, \ + { FL_FLOCK, "FL_FLOCK" }, \ + { FL_DELEG, "FL_DELEG" }, \ + { FL_ACCESS, "FL_ACCESS" }, \ + { FL_EXISTS, "FL_EXISTS" }, \ + { FL_LEASE, "FL_LEASE" }, \ + { FL_CLOSE, "FL_CLOSE" }, \ + { FL_SLEEP, "FL_SLEEP" }, \ + { FL_DOWNGRADE_PENDING, "FL_DOWNGRADE_PENDING" }, \ + { FL_UNLOCK_PENDING, "FL_UNLOCK_PENDING" }, \ + { FL_OFDLCK, "FL_OFDLCK" }) + +#define show_fl_type(val) \ + __print_symbolic(val, \ + { F_RDLCK, "F_RDLCK" }, \ + { F_WRLCK, "F_WRLCK" }, \ + { F_UNLCK, "F_UNLCK" }) + +DECLARE_EVENT_CLASS(filelock_lease, + + TP_PROTO(struct inode *inode, struct file_lock *fl), + + TP_ARGS(inode, fl), + + TP_STRUCT__entry( + __field(struct file_lock *, fl) + __field(unsigned long, i_ino) + __field(dev_t, s_dev) + __field(struct file_lock *, fl_next) + __field(fl_owner_t, fl_owner) + __field(unsigned int, fl_flags) + __field(unsigned char, fl_type) + __field(unsigned long, fl_break_time) + __field(unsigned long, fl_downgrade_time) + ), + + TP_fast_assign( + __entry->fl = fl; + __entry->s_dev = inode->i_sb->s_dev; + __entry->i_ino = inode->i_ino; + __entry->fl_next = fl->fl_next; + __entry->fl_owner = fl->fl_owner; + __entry->fl_flags = fl->fl_flags; + __entry->fl_type = fl->fl_type; + __entry->fl_break_time = fl->fl_break_time; + __entry->fl_downgrade_time = fl->fl_downgrade_time; + ), + + TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu", + __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev), + __entry->i_ino, __entry->fl_next, __entry->fl_owner, + show_fl_flags(__entry->fl_flags), + show_fl_type(__entry->fl_type), + __entry->fl_break_time, __entry->fl_downgrade_time) +); + +DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, generic_add_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +#endif /* _TRACE_FILELOCK_H */ + +/* This part must be outside protection */ +#include diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 95e46c8e05f90db319b2828eb53aa93bdca0629d..7543b3e51331fcb38574e3f309713b3a6a2d31c0 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -132,6 +132,22 @@ #define F_GETOWNER_UIDS 17 #endif +/* + * Open File Description Locks + * + * Usually record locks held by a process are released on *any* close and are + * not inherited across a fork(). + * + * These cmd values will set locks that conflict with process-associated + * record locks, but are "owned" by the open file description, not the + * process. This means that they are inherited across fork() like BSD (flock) + * locks, and they are only released automatically when the last reference to + * the the open file against which they were acquired is put. + */ +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + #define F_OWNER_TID 0 #define F_OWNER_PID 1 #define F_OWNER_PGRP 2 @@ -186,8 +202,6 @@ struct flock { }; #endif -#ifndef CONFIG_64BIT - #ifndef HAVE_ARCH_STRUCT_FLOCK64 #ifndef __ARCH_FLOCK64_PAD #define __ARCH_FLOCK64_PAD @@ -202,6 +216,5 @@ struct flock64 { __ARCH_FLOCK64_PAD }; #endif -#endif /* !CONFIG_64BIT */ #endif /* _ASM_GENERIC_FCNTL_H */ diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 0c146917c0497d457c64f1485808cb27d7febf6d..34e767e051530367ecef16b42fd80922a8cd73e3 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -20,6 +20,7 @@ #ifndef _UAPI_LINUX_BINDER_H #define _UAPI_LINUX_BINDER_H +#include #include #define B_PACK_CHARS(c1, c2, c3, c4) \ @@ -36,9 +37,64 @@ enum { BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), }; -enum { +/** + * enum flat_binder_object_shifts: shift values for flat_binder_object_flags + * @FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT: shift for getting scheduler policy. + * + */ +enum flat_binder_object_shifts { + FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT = 9, +}; + +/** + * enum flat_binder_object_flags - flags for use in flat_binder_object.flags + */ +enum flat_binder_object_flags { + /** + * @FLAT_BINDER_FLAG_PRIORITY_MASK: bit-mask for min scheduler priority + * + * These bits can be used to set the minimum scheduler priority + * at which transactions into this node should run. Valid values + * in these bits depend on the scheduler policy encoded in + * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK. + * + * For SCHED_NORMAL/SCHED_BATCH, the valid range is between [-20..19] + * For SCHED_FIFO/SCHED_RR, the value can run between [1..99] + */ FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, + /** + * @FLAT_BINDER_FLAG_ACCEPTS_FDS: whether the node accepts fds. + */ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, + /** + * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK: bit-mask for scheduling policy + * + * These two bits can be used to set the min scheduling policy at which + * transactions on this node should run. These match the UAPI + * scheduler policy values, eg: + * 00b: SCHED_NORMAL + * 01b: SCHED_FIFO + * 10b: SCHED_RR + * 11b: SCHED_BATCH + */ + FLAT_BINDER_FLAG_SCHED_POLICY_MASK = + 3U << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT, + + /** + * @FLAT_BINDER_FLAG_INHERIT_RT: whether the node inherits RT policy + * + * Only when set, calls into this node will inherit a real-time + * scheduling policy from the caller (for synchronous transactions). + */ + FLAT_BINDER_FLAG_INHERIT_RT = 0x800, + + /** + * @FLAT_BINDER_FLAG_TXN_SECURITY_CTX: request security contexts + * + * Only when set, causes senders to include their security + * context + */ + FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000, }; #ifdef BINDER_IPC_32BIT @@ -185,13 +241,53 @@ struct binder_version { #define BINDER_CURRENT_PROTOCOL_VERSION 8 #endif +/* + * Use with BINDER_GET_NODE_DEBUG_INFO, driver reads ptr, writes to all fields. + * Set ptr to NULL for the first call to get the info for the first node, and + * then repeat the call passing the previously returned value to get the next + * nodes. ptr will be 0 when there are no more nodes. + */ +struct binder_node_debug_info { + binder_uintptr_t ptr; + binder_uintptr_t cookie; + __u32 has_strong_ref; + __u32 has_weak_ref; +}; + +struct binder_node_info_for_ref { + __u32 handle; + __u32 strong_count; + __u32 weak_count; + __u32 reserved1; + __u32 reserved2; + __u32 reserved3; +}; + +struct binder_freeze_info { + __u32 pid; + __u32 enable; + __u32 timeout_ms; +}; + +struct binder_frozen_status_info { + __u32 pid; + __u32 sync_recv; + __u32 async_recv; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) -#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) -#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) -#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) -#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) -#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) +#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) +#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) +#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) +#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) +#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) +#define BINDER_SET_INHERIT_FIFO_PRIO _IO('b', 10) +#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) +#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) +#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) +#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) +#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info) /* * NOTE: Two special error codes you should check for when calling @@ -250,6 +346,11 @@ struct binder_transaction_data { } data; }; +struct binder_transaction_data_secctx { + struct binder_transaction_data transaction_data; + binder_uintptr_t secctx; +}; + struct binder_transaction_data_sg { struct binder_transaction_data transaction_data; binder_size_t buffers_size; @@ -263,7 +364,7 @@ struct binder_ptr_cookie { struct binder_handle_cookie { __u32 handle; binder_uintptr_t cookie; -} __packed; +} __attribute__((packed)); struct binder_pri_desc { __s32 priority; @@ -285,6 +386,11 @@ enum binder_driver_return_protocol { BR_OK = _IO('r', 1), /* No parameters! */ + BR_TRANSACTION_SEC_CTX = _IOR('r', 2, + struct binder_transaction_data_secctx), + /* + * binder_transaction_data_secctx: the received command. + */ BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), BR_REPLY = _IOR('r', 3, struct binder_transaction_data), /* @@ -362,6 +468,12 @@ enum binder_driver_return_protocol { * The the last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. */ + + BR_FROZEN_REPLY = _IO('r', 18), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is frozen. No parameters. + */ }; enum binder_driver_command_protocol { @@ -421,13 +533,15 @@ enum binder_driver_command_protocol { * of looping threads it has available. */ - BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_handle_cookie), + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, + struct binder_handle_cookie), /* * int: handle * void *: cookie */ - BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie), + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, + struct binder_handle_cookie), /* * int: handle * void *: cookie diff --git a/include/uapi/linux/android/binderfs.h b/include/uapi/linux/android/binderfs.h new file mode 100644 index 0000000000000000000000000000000000000000..65b2efd1a0a542bfa17deeb2f1ee7aff5f91e6de --- /dev/null +++ b/include/uapi/linux/android/binderfs.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2018 Canonical Ltd. + * + */ + +#ifndef _UAPI_LINUX_BINDER_CTL_H +#define _UAPI_LINUX_BINDER_CTL_H + +#include +#include +#include + +#define BINDERFS_MAX_NAME 255 + +/** + * struct binderfs_device - retrieve information about a new binder device + * @name: the name to use for the new binderfs binder device + * @major: major number allocated for binderfs binder devices + * @minor: minor number allocated for the new binderfs binder device + * + */ +struct binderfs_device { + char name[BINDERFS_MAX_NAME + 1]; + __u8 major; + __u8 minor; +}; + +/** + * Allocate a new binder device. + */ +#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device) + +#endif /* _UAPI_LINUX_BINDER_CTL_H */ + diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index 2835b85fd46d85ae47ec857caa93db1ee5ba79b9..e9502dd1ee2cc178e712e6ab05c59efecdaf980f 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h @@ -56,6 +56,8 @@ #define TUNGETVNETHDRSZ _IOR('T', 215, int) #define TUNSETVNETHDRSZ _IOW('T', 216, int) #define TUNSETQUEUE _IOW('T', 217, int) +#define TUNSETIFINDEX _IOW('T', 218, unsigned int) +#define TUNGETFILTER _IOR('T', 219, struct sock_fprog) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 @@ -68,6 +70,12 @@ #define IFF_MULTI_QUEUE 0x0100 #define IFF_ATTACH_QUEUE 0x0200 #define IFF_DETACH_QUEUE 0x0400 +/* read-only flag */ +#define IFF_PERSIST 0x0800 +#define IFF_NOFILTER 0x1000 + +/* Socket options */ +#define TUN_TX_TIMESTAMP 1 /* Features for GSO (TUNSETOFFLOAD). */ #define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index fc9697a766887707ae2b553269949cf3bbcd33cd..0ee2b194fbc038e17f83c7a6d4b1e12bd24b57f6 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -65,6 +65,7 @@ #define BDEVFS_MAGIC 0x62646576 #define BINFMTFS_MAGIC 0x42494e4d #define DEVPTS_SUPER_MAGIC 0x1cd1 +#define BINDERFS_SUPER_MAGIC 0x6c6f6f70 #define FUTEXFS_SUPER_MAGIC 0xBAD1DEA #define PIPEFS_MAGIC 0x50495045 #define PROC_SUPER_MAGIC 0x9fa0 diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a5d54770b91f79f9e6c0f79213118cdb69094a0d..98b0ba077c7ce0d7e8c9cb0e7e169c9c5ae986d8 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -205,7 +205,11 @@ * the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC * or, if no MAC address given, all stations, on the interface identified - * by %NL80211_ATTR_IFINDEX. + * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and + * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type + * of disconnection indication should be sent to the station + * (Deauthentication or Disassociation frame and reason code for that + * frame). * * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by diff --git a/include/uapi/linux/sockios.h b/include/uapi/linux/sockios.h index f7ffe36db03c4d8a1b9de218a8c402e24bd6e87f..01ee68ae7d1bb31bd3239cf4ad9665d12c965189 100644 --- a/include/uapi/linux/sockios.h +++ b/include/uapi/linux/sockios.h @@ -24,6 +24,8 @@ #define SIOCINQ FIONREAD #define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ +#define SOCK_IOC_TYPE 0x89 + /* Routing table calls. */ #define SIOCADDRT 0x890B /* add routing table entry */ #define SIOCDELRT 0x890C /* delete routing table entry */ diff --git a/init/Kconfig b/init/Kconfig index be1c0ceca2284070ec8fd8c5879c6c5978b27a0e..012ff71e4530ec4accd9104b9f20939176a2c061 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1572,6 +1572,7 @@ choice config SLAB bool "SLAB" + select HAVE_HARDENED_USERCOPY_ALLOCATOR help The regular slab allocator that is established and known to work well in all environments. It organizes cache hot objects in @@ -1579,6 +1580,7 @@ config SLAB config SLUB bool "SLUB (Unqueued Allocator)" + select HAVE_HARDENED_USERCOPY_ALLOCATOR help SLUB is a slab allocator that minimizes cache line usage instead of managing queues of cached objects (SLAB approach). diff --git a/kernel/futex.c b/kernel/futex.c index f1b1a81f9cffacf4522ef66a5d510e40ce5a1085..9ece806f173aa0a1c67c100cc2b70579468086e9 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -456,7 +456,7 @@ again: key->both.offset |= FUT_OFF_INODE; /* inode-based key */ key->shared.inode = inode; - key->shared.pgoff = basepage_index(page); + key->shared.pgoff = page_head->index; rcu_read_unlock(); } diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 6a9d6af4dd86935bce6f40183f365d288067ce07..3955bef8f3bcd71999b53f9b9474a093b090b2ec 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -327,3 +327,14 @@ config WAKEUP_IRQ_DEBUG ---help--- This enables debug information about wakeup interrupts using sysfs (/sys/kernel/). + +config PARTIALRESUME + bool "Partial-resume framework" + ---help--- + Provides hooks for drivers to register partial-resume handlers. + Similar to suspend_again support already in kernel, except that it + operates with kernel threads unfrozen and userspace still frozen, + allowing callbacks to block on work queues and kernel threads. + Partial resume will occur only if all wakeup sources have + partial-resume handlers associated with them, and they all return + true. diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 845b34bcd4d5cff86afc378786f5dae6d289f8dd..6dcf5bd75a7bc25cdef94c4d6ab6b9143da6000e 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o obj-$(CONFIG_SUSPEND) += wakeup_reason.o obj-$(CONFIG_WAKEUP_IRQ_DEBUG) += wakeup_irq_debug.o +obj-$(CONFIG_PARTIALRESUME) += partialresume.o diff --git a/kernel/power/partialresume.c b/kernel/power/partialresume.c new file mode 100644 index 0000000000000000000000000000000000000000..295c3f755000594f9550da1fc0828f7b3d41007f --- /dev/null +++ b/kernel/power/partialresume.c @@ -0,0 +1,189 @@ +/* kernel/power/partialresume.c + * + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static DEFINE_MUTEX(pr_handlers_lock); +static LIST_HEAD(pr_handlers); +static LIST_HEAD(pr_matches); +static struct partial_resume_stats match_stats; +static struct partial_resume_stats consensus_stats; +static struct kobject *partialresume; + +bool suspend_again_match(const struct list_head *irqs, + const struct list_head *unfinished) +{ + const struct wakeup_irq_node *i; + struct partial_resume *h, *match; + + INIT_LIST_HEAD(&pr_matches); + + match_stats.total++; + + if (!irqs || list_empty(irqs)) + return false; + + list_for_each_entry(i, irqs, next) { + match = NULL; + list_for_each_entry(h, &pr_handlers, next_handler) { + if (i->irq == h->irq) { + match = h; + break; + } + } + if (!match) { + pr_debug("%s: wakeup irq %d does not have a handler\n", __func__, i->irq); + return false; + } + list_add(&match->next_match, &pr_matches); + } + + match_stats.total_yes++; + + return true; +} + + +bool suspend_again_consensus(void) +{ + struct partial_resume *h; + + BUG_ON(list_empty(&pr_matches)); + list_for_each_entry(h, &pr_matches, next_match) { + h->stats.total++; + if (!h->partial_resume(h)) { + pr_debug("%s: partial-resume for %d: false\n", __func__, h->irq); + return false; + } + h->stats.total_yes++; + pr_debug("%s: partial-resume for %d: true\n", __func__, h->irq); + } + + consensus_stats.total_yes++; + + return true; +} + + +int register_partial_resume(struct partial_resume *handler) +{ + struct partial_resume *e; + + if (!handler || !handler->irq || !handler->partial_resume) + return -EINVAL; + + mutex_lock(&pr_handlers_lock); + list_for_each_entry(e, &pr_handlers, next_handler) { + if (e->irq == handler->irq) { + if (e->partial_resume == handler->partial_resume) + return 0; + pr_err("%s: error registering %pF for irq %d: "\ + "%pF already registered\n", + __func__, + handler->partial_resume, + e->irq, + e->partial_resume); + mutex_unlock(&pr_handlers_lock); + return -EIO; + } + } + + list_add(&handler->next_handler, &pr_handlers); + mutex_unlock(&pr_handlers_lock); + return 0; +} + +void unregister_partial_resume(struct partial_resume *handler) +{ + mutex_lock(&pr_handlers_lock); + list_del(&handler->next_handler); + mutex_unlock(&pr_handlers_lock); +} + + +static ssize_t partialresume_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + ssize_t offset = 0; + struct partial_resume *h; + + offset += sprintf(buf + offset, "global: %d %d %d \n", + match_stats.total, + match_stats.total_yes, + consensus_stats.total_yes); + + mutex_lock(&pr_handlers_lock); + + list_for_each_entry(h, &pr_handlers, next_handler) { + offset += sprintf(buf + offset, "%d: %d %d\n", + h->irq, + h->stats.total, + h->stats.total_yes); + } + + mutex_unlock(&pr_handlers_lock); + + return offset; +} + +static struct kobj_attribute partialresume_stats = __ATTR_RO(partialresume_stats); + +static struct attribute *partialresume_stats_attrs[] = { + &partialresume_stats.attr, + NULL, +}; +static struct attribute_group partialresume_stats_attr_group = { + .attrs = partialresume_stats_attrs, +}; + +int __init partial_resume_init(void) +{ + int rc = -EIO; + + partialresume = kobject_create_and_add("partialresume", kernel_kobj); + if (!partialresume) { + pr_warning("%s: failed to create a sysfs kobject\n", __func__); + goto fail; + } + + rc = sysfs_create_group(partialresume, &partialresume_stats_attr_group); + if (rc) { + pr_warning("%s: failed to create a sysfs group\n", __func__); + goto fail_kobject_put; + } + + return 0; + +#if 0 +fail_remove_group: + sysfs_remove_group(partialresume, &partialresume_stats_attr_group); +#endif +fail_kobject_put: + kobject_put(partialresume); +fail: + return rc; +} + +subsys_initcall(partial_resume_init); diff --git a/kernel/softirq.c b/kernel/softirq.c index 96a4c2828ce6512c094da01fd6d77afd15e9c493..2dd7dae55efebac226f04c788b6568e945bd7187 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -125,8 +125,7 @@ static inline void __local_bh_disable(unsigned long ip, unsigned int cnt) void local_bh_disable(void) { - __local_bh_disable((unsigned long)__builtin_return_address(0), - SOFTIRQ_DISABLE_OFFSET); + __local_bh_disable(_RET_IP_, SOFTIRQ_DISABLE_OFFSET); } EXPORT_SYMBOL(local_bh_disable); @@ -137,7 +136,7 @@ static void __local_bh_enable(unsigned int cnt) WARN_ON_ONCE(!irqs_disabled()); if (softirq_count() == cnt) - trace_softirqs_on((unsigned long)__builtin_return_address(0)); + trace_softirqs_on(_RET_IP_); sub_preempt_count(cnt); } @@ -182,7 +181,7 @@ static inline void _local_bh_enable_ip(unsigned long ip) void local_bh_enable(void) { - _local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + _local_bh_enable_ip(_RET_IP_); } EXPORT_SYMBOL(local_bh_enable); @@ -227,8 +226,7 @@ asmlinkage void __do_softirq(void) pending = local_softirq_pending(); account_irq_enter_time(current); - __local_bh_disable((unsigned long)__builtin_return_address(0), - SOFTIRQ_OFFSET); + __local_bh_disable(_RET_IP_, SOFTIRQ_OFFSET); lockdep_softirq_enter(); cpu = smp_processor_id(); diff --git a/lib/Makefile b/lib/Makefile index 5dd3fed4b11406ae9c501beef02d8699e0135f0b..ae77e3f6daa7b9720d2dd3223f16594857659edd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -24,7 +24,8 @@ lib-y += kobject.o klist.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o \ - bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o + bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o refcount.o + obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o obj-y += kstrtox.o diff --git a/lib/refcount.c b/lib/refcount.c new file mode 100644 index 0000000000000000000000000000000000000000..e67419c90d4ff6fbd4bb1d4563a4f6652e382346 --- /dev/null +++ b/lib/refcount.c @@ -0,0 +1,393 @@ +/* + * Variant of atomic_t specialized for reference counts. + * + * The interface matches the atomic_t interface (to aid in porting) but only + * provides the few functions one should use for reference counting. + * + * It differs in that the counter saturates at REFCOUNT_SATURATED and will not + * move once there. This avoids wrapping the counter and causing 'spurious' + * use-after-free issues. + * + * Memory ordering rules are slightly relaxed wrt regular atomic_t functions + * and provide only what is strictly required for refcounts. + * + * The increments are fully relaxed; these will not provide ordering. The + * rationale is that whatever is used to obtain the object we're increasing the + * reference count on will provide the ordering. For locked data structures, + * its the lock acquire, for RCU/lockless data structures its the dependent + * load. + * + * Do note that inc_not_zero() provides a control dependency which will order + * future stores against the inc, this ensures we'll never modify the object + * if we did not in fact acquire a reference. + * + * The decrements will provide release order, such that all the prior loads and + * stores will be issued before, it also provides a control dependency, which + * will order us against the subsequent free(). + * + * The control dependency is against the load of the cmpxchg (ll/sc) that + * succeeded. This means the stores aren't fully ordered, but this is fine + * because the 1->0 transition indicates no concurrency. + * + * Note that the allocator is responsible for ordering things between free() + * and alloc(). + * + * The decrements dec_and_test() and sub_and_test() also provide acquire + * ordering on success. + * + */ + +#include +#include +#include +#include + +#ifdef CONFIG_REFCOUNT_FULL + +/** + * refcount_add_not_zero - add a value to a refcount unless it is 0 + * @i: the value to add to the refcount + * @r: the refcount + * + * Will saturate at REFCOUNT_SATURATED and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_inc(), or one of its variants, should instead be used to + * increment a reference count. + * + * Return: false if the passed refcount is 0, true otherwise + */ +bool refcount_add_not_zero(int i, refcount_t *r) +{ + unsigned int new, val = atomic_read(&r->refs); + + do { + if (!val) + return false; + + if (unlikely(val == REFCOUNT_SATURATED)) + return true; + + new = val + i; + if (new < val) + new = REFCOUNT_SATURATED; + + } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); + + WARN_ONCE(new == REFCOUNT_SATURATED, + "refcount_t: saturated; leaking memory.\n"); + + return true; +} +EXPORT_SYMBOL(refcount_add_not_zero); + +/** + * refcount_add - add a value to a refcount + * @i: the value to add to the refcount + * @r: the refcount + * + * Similar to atomic_add(), but will saturate at REFCOUNT_SATURATED and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_inc(), or one of its variants, should instead be used to + * increment a reference count. + */ +void refcount_add(int i, refcount_t *r) +{ + WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); +} +EXPORT_SYMBOL(refcount_add); + +/** + * refcount_inc_not_zero - increment a refcount unless it is 0 + * @r: the refcount to increment + * + * Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED + * and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + * + * Return: true if the increment was successful, false otherwise + */ +bool refcount_inc_not_zero(refcount_t *r) +{ + unsigned int new, val = atomic_read(&r->refs); + + do { + new = val + 1; + + if (!val) + return false; + + if (unlikely(!new)) + return true; + + } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); + + WARN_ONCE(new == REFCOUNT_SATURATED, + "refcount_t: saturated; leaking memory.\n"); + + return true; +} +EXPORT_SYMBOL(refcount_inc_not_zero); + +/** + * refcount_inc - increment a refcount + * @r: the refcount to increment + * + * Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN. + * + * Provides no memory ordering, it is assumed the caller already has a + * reference on the object. + * + * Will WARN if the refcount is 0, as this represents a possible use-after-free + * condition. + */ +void refcount_inc(refcount_t *r) +{ + WARN_ONCE(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); +} +EXPORT_SYMBOL(refcount_inc); + +/** + * refcount_sub_and_test - subtract from a refcount and test if it is 0 + * @i: amount to subtract from the refcount + * @r: the refcount + * + * Similar to atomic_dec_and_test(), but it will WARN, return false and + * ultimately leak on underflow and will fail to decrement when saturated + * at REFCOUNT_SATURATED. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides an acquire ordering on success such that free() + * must come after. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_dec(), or one of its variants, should instead be used to + * decrement a reference count. + * + * Return: true if the resulting refcount is 0, false otherwise + */ +bool refcount_sub_and_test(int i, refcount_t *r) +{ + unsigned int new, val = atomic_read(&r->refs); + + do { + if (unlikely(val == REFCOUNT_SATURATED)) + return false; + + new = val - i; + if (new > val) { + WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); + return false; + } + + } while (!atomic_try_cmpxchg_release(&r->refs, &val, new)); + + if (!new) { + smp_acquire__after_ctrl_dep(); + return true; + } + return false; + +} +EXPORT_SYMBOL(refcount_sub_and_test); + +/** + * refcount_dec_and_test - decrement a refcount and test if it is 0 + * @r: the refcount + * + * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to + * decrement when saturated at REFCOUNT_SATURATED. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides an acquire ordering on success such that free() + * must come after. + * + * Return: true if the resulting refcount is 0, false otherwise + */ +bool refcount_dec_and_test(refcount_t *r) +{ + return refcount_sub_and_test(1, r); +} +EXPORT_SYMBOL(refcount_dec_and_test); + +/** + * refcount_dec - decrement a refcount + * @r: the refcount + * + * Similar to atomic_dec(), it will WARN on underflow and fail to decrement + * when saturated at REFCOUNT_SATURATED. + * + * Provides release memory ordering, such that prior loads and stores are done + * before. + */ +void refcount_dec(refcount_t *r) +{ + WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); +} +EXPORT_SYMBOL(refcount_dec); + +#endif /* CONFIG_REFCOUNT_FULL */ + +/** + * refcount_dec_if_one - decrement a refcount if it is 1 + * @r: the refcount + * + * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the + * success thereof. + * + * Like all decrement operations, it provides release memory order and provides + * a control dependency. + * + * It can be used like a try-delete operator; this explicit case is provided + * and not cmpxchg in generic, because that would allow implementing unsafe + * operations. + * + * Return: true if the resulting refcount is 0, false otherwise + */ +bool refcount_dec_if_one(refcount_t *r) +{ + int val = 1; + + return atomic_try_cmpxchg_release(&r->refs, &val, 0); +} +EXPORT_SYMBOL(refcount_dec_if_one); + +/** + * refcount_dec_not_one - decrement a refcount if it is not 1 + * @r: the refcount + * + * No atomic_t counterpart, it decrements unless the value is 1, in which case + * it will return false. + * + * Was often done like: atomic_add_unless(&var, -1, 1) + * + * Return: true if the decrement operation was successful, false otherwise + */ +bool refcount_dec_not_one(refcount_t *r) +{ + unsigned int new, val = atomic_read(&r->refs); + + do { + if (unlikely(val == REFCOUNT_SATURATED)) + return true; + + if (val == 1) + return false; + + new = val - 1; + if (new > val) { + WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); + return true; + } + + } while (!atomic_try_cmpxchg_release(&r->refs, &val, new)); + + return true; +} +EXPORT_SYMBOL(refcount_dec_not_one); + +/** + * refcount_dec_and_mutex_lock - return holding mutex if able to decrement + * refcount to 0 + * @r: the refcount + * @lock: the mutex to be locked + * + * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail + * to decrement when saturated at REFCOUNT_SATURATED. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + * + * Return: true and hold mutex if able to decrement refcount to 0, false + * otherwise + */ +bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) +{ + if (refcount_dec_not_one(r)) + return false; + + mutex_lock(lock); + if (!refcount_dec_and_test(r)) { + mutex_unlock(lock); + return false; + } + + return true; +} +EXPORT_SYMBOL(refcount_dec_and_mutex_lock); + +/** + * refcount_dec_and_lock - return holding spinlock if able to decrement + * refcount to 0 + * @r: the refcount + * @lock: the spinlock to be locked + * + * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to + * decrement when saturated at REFCOUNT_SATURATED. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + * + * Return: true and hold spinlock if able to decrement refcount to 0, false + * otherwise + */ +bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) +{ + if (refcount_dec_not_one(r)) + return false; + + spin_lock(lock); + if (!refcount_dec_and_test(r)) { + spin_unlock(lock); + return false; + } + + return true; +} +EXPORT_SYMBOL(refcount_dec_and_lock); + +/** + * refcount_dec_and_lock_irqsave - return holding spinlock with disabled + * interrupts if able to decrement refcount to 0 + * @r: the refcount + * @lock: the spinlock to be locked + * @flags: saved IRQ-flags if the is acquired + * + * Same as refcount_dec_and_lock() above except that the spinlock is acquired + * with disabled interupts. + * + * Return: true and hold spinlock if able to decrement refcount to 0, false + * otherwise + */ +bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock, + unsigned long *flags) +{ + if (refcount_dec_not_one(r)) + return false; + + spin_lock_irqsave(lock, *flags); + if (!refcount_dec_and_test(r)) { + spin_unlock_irqrestore(lock, *flags); + return false; + } + + return true; +} +EXPORT_SYMBOL(refcount_dec_and_lock_irqsave); diff --git a/mm/Kconfig b/mm/Kconfig index 67d2b863141c4746512e956c4ccface2a101e15b..9d6d85927e65cb1dc91e2b0bb8844ca11d5b254e 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -623,3 +623,6 @@ config VM_MAX_READAHEAD This sets the VM_MAX_READAHEAD value to allow the readahead window to grow to a maximum size of configured. This will benefit sequential read throughput and thus early boot performance. + +config KMAP_LOCAL + bool diff --git a/mm/Makefile b/mm/Makefile index 55fff061a125cbeadf1d77ea1ab7ba8dac587447..9abb601d99f0cfdf57e18fc4812478eb5ef7a3c2 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -17,7 +17,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ util.o mmzone.o vmstat.o backing-dev.o \ mm_init.o mmu_context.o percpu.o slab_common.o \ compaction.o balloon_compaction.o \ - interval_tree.o $(mmu-y) \ + interval_tree.o list_lru.o $(mmu-y) \ showmem.o vmpressure.o obj-y += init-mm.o @@ -66,3 +66,4 @@ obj-$(CONFIG_Z3FOLD) += z3fold.o obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o obj-$(CONFIG_ZPOOL) += zpool.o obj-$(CONFIG_ZSMALLOC) += zsmalloc.o +obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o diff --git a/mm/highmem.c b/mm/highmem.c index b32b70cdaed6cba1ba79914228593441f4b312d3..817a62b2cccf293bfe0486fd43c2dd7389d7121e 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -30,9 +30,11 @@ #include +#ifndef CONFIG_KMAP_LOCAL #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) DEFINE_PER_CPU(int, __kmap_atomic_idx); #endif +#endif /* * Virtual_count is not a pure "count". @@ -307,8 +309,146 @@ void kunmap_high(struct page *page) if (need_wakeup) wake_up(&pkmap_map_wait); } - EXPORT_SYMBOL(kunmap_high); +#endif /* CONFIG_HIGHMEM */ + +#ifdef CONFIG_KMAP_LOCAL + +#include + +static DEFINE_PER_CPU(int, __kmap_local_idx); + +static inline int kmap_local_idx_push(void) +{ + int idx = __this_cpu_inc_return(__kmap_local_idx) - 1; + + WARN_ON_ONCE(in_irq() && !irqs_disabled()); + BUG_ON(idx >= KM_MAX_IDX); + return idx; +} + +static inline int kmap_local_idx(void) +{ + return __this_cpu_read(__kmap_local_idx) - 1; +} + +static inline void kmap_local_idx_pop(void) +{ + int idx = __this_cpu_dec_return(__kmap_local_idx); + + BUG_ON(idx < 0); +} + +#ifndef arch_kmap_local_post_map +# define arch_kmap_local_post_map(vaddr, pteval) do { } while (0) +#endif +#ifndef arch_kmap_local_pre_unmap +# define arch_kmap_local_pre_unmap(vaddr) do { } while (0) +#endif + +#ifndef arch_kmap_local_post_unmap +# define arch_kmap_local_post_unmap(vaddr) do { } while (0) +#endif + +#ifndef arch_kmap_local_map_idx +#define arch_kmap_local_map_idx(idx, pfn) kmap_local_calc_idx(idx) +#endif + +#ifndef arch_kmap_local_unmap_idx +#define arch_kmap_local_unmap_idx(idx, vaddr) kmap_local_calc_idx(idx) +#endif + +#ifndef arch_kmap_local_high_get +static inline void *arch_kmap_local_high_get(struct page *page) +{ + return NULL; +} +#endif + +/* Unmap a local mapping which was obtained by kmap_high_get() */ +static inline void kmap_high_unmap_local(unsigned long vaddr) +{ +#ifdef ARCH_NEEDS_KMAP_HIGH_GET + if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) + kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)])); +#endif +} + +static inline int kmap_local_calc_idx(int idx) +{ + return idx + KM_MAX_IDX * smp_processor_id(); +} + +static pte_t *__kmap_pte; + +static pte_t *kmap_get_pte(void) +{ + if (!__kmap_pte) + __kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN)); + return __kmap_pte; +} + +void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot) +{ + pte_t pteval, *kmap_pte = kmap_get_pte(); + unsigned long vaddr; + int idx; + + preempt_disable(); + idx = arch_kmap_local_map_idx(kmap_local_idx_push(), pfn); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + BUG_ON(!pte_none(*(kmap_pte - idx))); + pteval = pfn_pte(pfn, prot); + set_pte_at(&init_mm, vaddr, kmap_pte - idx, pteval); + arch_kmap_local_post_map(vaddr, pteval); + preempt_enable(); + + return (void *)vaddr; +} +EXPORT_SYMBOL_GPL(__kmap_local_pfn_prot); + +void *__kmap_local_page_prot(struct page *page, pgprot_t prot) +{ + void *kmap; + + if (!PageHighMem(page)) + return page_address(page); + + /* Try kmap_high_get() if architecture has it enabled */ + kmap = arch_kmap_local_high_get(page); + if (kmap) + return kmap; + + return __kmap_local_pfn_prot(page_to_pfn(page), prot); +} +EXPORT_SYMBOL(__kmap_local_page_prot); + +void kunmap_local_indexed(void *vaddr) +{ + unsigned long addr = (unsigned long) vaddr & PAGE_MASK; + pte_t *kmap_pte = kmap_get_pte(); + int idx; + + if (addr < __fix_to_virt(FIX_KMAP_END) || + addr > __fix_to_virt(FIX_KMAP_BEGIN)) { + WARN_ON_ONCE(addr < PAGE_OFFSET); + + /* Handle mappings which were obtained by kmap_high_get() */ + kmap_high_unmap_local(addr); + return; + } + + preempt_disable(); + idx = arch_kmap_local_unmap_idx(kmap_local_idx(), addr); + WARN_ON_ONCE(addr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); + + arch_kmap_local_pre_unmap(addr); + pte_clear(&init_mm, addr, kmap_pte - idx); + arch_kmap_local_post_unmap(addr); + kmap_local_idx_pop(); + preempt_enable(); +} +EXPORT_SYMBOL(kunmap_local_indexed); #endif #if defined(HASHED_PAGE_VIRTUAL) diff --git a/mm/list_lru.c b/mm/list_lru.c new file mode 100644 index 0000000000000000000000000000000000000000..8b0076a1f6815695c059dae617f5d0cf3deee061 --- /dev/null +++ b/mm/list_lru.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved. + * Authors: David Chinner and Glauber Costa + * + * Generic LRU infrastructure + */ +#include +#include +#include +#include + +bool list_lru_add(struct list_lru *lru, struct list_head *item) +{ + int nid = page_to_nid(virt_to_page(item)); + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); + WARN_ON_ONCE(nlru->nr_items < 0); + if (list_empty(item)) { + list_add_tail(item, &nlru->list); + if (nlru->nr_items++ == 0) + node_set(nid, lru->active_nodes); + spin_unlock(&nlru->lock); + return true; + } + spin_unlock(&nlru->lock); + return false; +} +EXPORT_SYMBOL_GPL(list_lru_add); + +bool list_lru_del(struct list_lru *lru, struct list_head *item) +{ + int nid = page_to_nid(virt_to_page(item)); + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); + if (!list_empty(item)) { + list_del_init(item); + if (--nlru->nr_items == 0) + node_clear(nid, lru->active_nodes); + WARN_ON_ONCE(nlru->nr_items < 0); + spin_unlock(&nlru->lock); + return true; + } + spin_unlock(&nlru->lock); + return false; +} +EXPORT_SYMBOL_GPL(list_lru_del); + +unsigned long +list_lru_count_node(struct list_lru *lru, int nid) +{ + unsigned long count = 0; + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); + WARN_ON_ONCE(nlru->nr_items < 0); + count += nlru->nr_items; + spin_unlock(&nlru->lock); + + return count; +} +EXPORT_SYMBOL_GPL(list_lru_count_node); + +unsigned long +list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, + void *cb_arg, unsigned long *nr_to_walk) +{ + + struct list_lru_node *nlru = &lru->node[nid]; + struct list_head *item, *n; + unsigned long isolated = 0; + + spin_lock(&nlru->lock); +restart: + list_for_each_safe(item, n, &nlru->list) { + enum lru_status ret; + + /* + * decrement nr_to_walk first so that we don't livelock if we + * get stuck on large numbesr of LRU_RETRY items + */ + if (!*nr_to_walk) + break; + --*nr_to_walk; + + ret = isolate(item, &nlru->lock, cb_arg); + switch (ret) { + case LRU_REMOVED: + if (--nlru->nr_items == 0) + node_clear(nid, lru->active_nodes); + WARN_ON_ONCE(nlru->nr_items < 0); + isolated++; + break; + case LRU_ROTATE: + list_move_tail(item, &nlru->list); + break; + case LRU_SKIP: + break; + case LRU_RETRY: + /* + * The lru lock has been dropped, our list traversal is + * now invalid and so we have to restart from scratch. + */ + goto restart; + default: + BUG(); + } + } + + spin_unlock(&nlru->lock); + return isolated; +} +EXPORT_SYMBOL_GPL(list_lru_walk_node); + +static unsigned long list_lru_dispose_all_node(struct list_lru *lru, int nid, + list_lru_dispose_cb dispose) +{ + struct list_lru_node *nlru = &lru->node[nid]; + LIST_HEAD(dispose_list); + unsigned long disposed = 0; + + spin_lock(&nlru->lock); + while (!list_empty(&nlru->list)) { + list_splice_init(&nlru->list, &dispose_list); + disposed += nlru->nr_items; + nlru->nr_items = 0; + node_clear(nid, lru->active_nodes); + spin_unlock(&nlru->lock); + + dispose(&dispose_list); + + spin_lock(&nlru->lock); + } + spin_unlock(&nlru->lock); + return disposed; +} + +unsigned long list_lru_dispose_all(struct list_lru *lru, + list_lru_dispose_cb dispose) +{ + unsigned long disposed; + unsigned long total = 0; + int nid; + + do { + disposed = 0; + for_each_node_mask(nid, lru->active_nodes) { + disposed += list_lru_dispose_all_node(lru, nid, + dispose); + } + total += disposed; + } while (disposed != 0); + + return total; +} + +int list_lru_init(struct list_lru *lru) +{ + int i; + + nodes_clear(lru->active_nodes); + for (i = 0; i < MAX_NUMNODES; i++) { + spin_lock_init(&lru->node[i].lock); + INIT_LIST_HEAD(&lru->node[i].list); + lru->node[i].nr_items = 0; + } + return 0; +} +EXPORT_SYMBOL_GPL(list_lru_init); diff --git a/mm/memory.c b/mm/memory.c index 3c5bc55c567b7ec1c6f8c995bb438503931b4fe4..2425ef9f4c664493d9a6d16e7c71d4ba30daffaf 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -128,7 +128,7 @@ static int __init init_zero_pfn(void) zero_pfn = page_to_pfn(ZERO_PAGE(0)); return 0; } -core_initcall(init_zero_pfn); +early_initcall(init_zero_pfn); #if defined(SPLIT_RSS_COUNTING) diff --git a/mm/mmap.c b/mm/mmap.c index 48cd61da289ebf271bcbee5421c025b121e13fb8..210ecd39da93f862403086e0d05141a72bfc864c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1318,7 +1318,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, /* * Make sure there are no mandatory locks on the file. */ - if (locks_verify_locked(inode)) + if (locks_verify_locked(file)) return -EAGAIN; vm_flags |= VM_SHARED | VM_MAYSHARE; diff --git a/mm/nommu.c b/mm/nommu.c index 75a3a2479d21aad589d3db426161c6f574cfde74..4d2d945829a73a1c4fec522dfd6057dcda21d8e6 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -993,7 +993,7 @@ static int validate_mmap_request(struct file *file, (file->f_mode & FMODE_WRITE)) return -EACCES; - if (locks_verify_locked(file_inode(file))) + if (locks_verify_locked(file)) return -EAGAIN; if (!(capabilities & BDI_CAP_MAP_DIRECT)) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8d646deb95166d6c3c7b7b2a8c5a1310ef56fb56..07188883cac199d5bf966616e9869aeeb704cfd7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -726,6 +727,8 @@ static bool free_pages_prepare(struct page *page, unsigned int order) int i; int bad = 0; + unsigned long index = 1UL << order; + trace_mm_page_free(page, order); kmemcheck_free_shadow(page, order); @@ -748,6 +751,10 @@ static bool free_pages_prepare(struct page *page, unsigned int order) debug_check_no_obj_freed(page_address(page), PAGE_SIZE << order); } + + for (; index; --index) + sanitize_highpage(page + index - 1); + arch_free_page(page, order); kernel_map_pages(page, 1 << order, 0); @@ -792,6 +799,16 @@ void __free_pages_bootmem(struct page *page, unsigned int order) set_page_count(p, 0); } + if (!PageHighMem(page) && page_to_pfn(page) < 0x100000) { + unsigned long hash = 0; + size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; + const unsigned long *data = lowmem_page_address(page); + + for (index = 0; index < end; index++) + hash ^= hash + data[index]; + add_device_randomness((const void *)&hash, sizeof(hash)); + } + page_zone(page)->managed_pages += 1 << order; set_page_refcounted(page); __free_pages(page, order); @@ -897,6 +914,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) { int i; + unsigned long index = 1UL << order; + for (i = 0; i < (1 << order); i++) { struct page *p = page + i; if (unlikely(check_new_page(p))) @@ -909,8 +928,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) arch_alloc_page(page, order); kernel_map_pages(page, 1 << order, 1); - if (gfp_flags & __GFP_ZERO) - prep_zero_page(page, order, gfp_flags); + for (; index; --index) + sanitize_highpage_verify(page + index - 1); if (order && (gfp_flags & __GFP_COMP)) prep_compound_page(page, order); diff --git a/mm/slab.c b/mm/slab.c index bd88411595b9ba1df48332a7e89d64847cd7de6e..5d0d88ad6ea769b62e0d92a0cadd5a1a69cddf45 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4483,6 +4483,37 @@ static int __init slab_proc_init(void) module_init(slab_proc_init); #endif +#ifdef CONFIG_HARDENED_USERCOPY +/* + * Rejects objects that are incorrectly sized. + * + * Returns NULL if check passes, otherwise const char * to name of cache + * to indicate an error. + */ +const char *__check_heap_object(const void *ptr, unsigned long n, + struct page *page) +{ + struct kmem_cache *cachep; + unsigned int objnr; + unsigned long offset; + + /* Find and validate object. */ + cachep = page->slab_cache; + objnr = obj_to_index(cachep, page->slab_page, (void *)ptr); + BUG_ON(objnr >= cachep->num); + + /* Find offset within object. */ + offset = ptr - index_to_obj(cachep, page->slab_page, objnr) - + obj_offset(cachep); + + /* Allow address range falling entirely within object size. */ + if (offset <= cachep->object_size && n <= cachep->object_size - offset) + return NULL; + + return cachep->name; +} +#endif /* CONFIG_HARDENED_USERCOPY */ + /** * ksize - get the actual amount of memory allocated for a given object * @objp: Pointer to the object diff --git a/mm/slab.h b/mm/slab.h index 4d6d836247dd95c3eb5e4d3e39295a80eb000a81..db27e934907662ec050eb55c036753597d6e918d 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -196,7 +196,7 @@ static inline void memcg_release_pages(struct kmem_cache *s, int order) static inline bool slab_equal_or_root(struct kmem_cache *s, struct kmem_cache *p) { - return true; + return p == s; } static inline const char *cache_name(struct kmem_cache *s) @@ -220,25 +220,14 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) struct kmem_cache *cachep; struct page *page; - /* - * When kmemcg is not being used, both assignments should return the - * same value. but we don't want to pay the assignment price in that - * case. If it is not compiled in, the compiler should be smart enough - * to not do even the assignment. In that case, slab_equal_or_root - * will also be a constant. - */ - if (!memcg_kmem_enabled() && !unlikely(s->flags & SLAB_DEBUG_FREE)) - return s; - page = virt_to_head_page(x); + BUG_ON(!PageSlab(page)); cachep = page->slab_cache; if (slab_equal_or_root(cachep, s)) return cachep; - pr_err("%s: Wrong slab cache. %s but object is from %s\n", + panic("%s: Wrong slab cache. %s but object is from %s\n", __FUNCTION__, cachep->name, s->name); - WARN_ON_ONCE(1); - return s; } #endif diff --git a/mm/slub.c b/mm/slub.c index bc6d52865a3785019a846cbc14af1b212802a0b7..f435c94e0573e1560219189d79fb198b1dbf793d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -123,6 +124,14 @@ static inline int kmem_cache_debug(struct kmem_cache *s) #endif } +static inline void *fixup_red_left(struct kmem_cache *s, void *p) +{ + if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) + p += s->red_left_pad; + + return p; +} + /* * Issues still to be resolved: * @@ -198,6 +207,8 @@ struct track { enum track_item { TRACK_ALLOC, TRACK_FREE }; +static const bool slub_cookie = true; + #ifdef CONFIG_SYSFS static int sysfs_slab_add(struct kmem_cache *); static int sysfs_slab_alias(struct kmem_cache *, const char *); @@ -248,20 +259,28 @@ static inline int check_valid_pointer(struct kmem_cache *s, static inline void *get_freepointer(struct kmem_cache *s, void *object) { - return *(void **)(object + s->offset); + unsigned long freepointer_addr = (unsigned long)object + s->offset; + return (void *)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); } static void prefetch_freepointer(const struct kmem_cache *s, void *object) { - prefetch(object + s->offset); + unsigned long freepointer_addr = (unsigned long)object + s->offset; + if (object) { + void **freepointer_ptr = (void **)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); + prefetch(freepointer_ptr); + } } static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) { + unsigned long __maybe_unused freepointer_addr; void *p; #ifdef CONFIG_DEBUG_PAGEALLOC - probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p)); + freepointer_addr = (unsigned long)object + s->offset; + probe_kernel_read(&p, (void **)freepointer_addr, sizeof(p)); + return (void *)((unsigned long)p ^ s->random ^ freepointer_addr); #else p = get_freepointer(s, object); #endif @@ -270,13 +289,50 @@ static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) { - *(void **)(object + s->offset) = fp; + unsigned long freepointer_addr = (unsigned long)object + s->offset; + *(void **)freepointer_addr = (void *)((unsigned long)fp ^ s->random ^ freepointer_addr); +} + +#ifdef CONFIG_64BIT +static const unsigned long canary_mask = ~0xFFUL; +#else +static const unsigned long canary_mask = ~0UL; +#endif + +static inline unsigned long *get_cookie(struct kmem_cache *s, void *object) +{ + if (s->offset) + return object + s->offset + sizeof(void *); + else + return object + s->inuse; +} + +static inline void set_cookie(struct kmem_cache *s, void *object, unsigned long value) +{ + if (slub_cookie) { + unsigned long *cookie = get_cookie(s, object); + *cookie = (value ^ (unsigned long)cookie) & canary_mask; + } +} + +static inline void check_cookie(struct kmem_cache *s, void *object, unsigned long value) +{ + if (slub_cookie) { + unsigned long *cookie = get_cookie(s, object); + BUG_ON(*cookie != ((value ^ (unsigned long)cookie) & canary_mask)); + } } /* Loop over all objects in a slab */ #define for_each_object(__p, __s, __addr, __objects) \ - for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\ - __p += (__s)->size) + for (__p = fixup_red_left(__s, __addr); \ + __p < (__addr) + (__objects) * (__s)->size; \ + __p += (__s)->size) + +#define for_each_object_idx(__p, __idx, __s, __addr, __objects) \ + for (__p = fixup_red_left(__s, __addr), __idx = 1; \ + __idx <= __objects; \ + __p += (__s)->size, __idx++) /* Determine object index from a given position */ static inline int slab_index(void *p, struct kmem_cache *s, void *addr) @@ -300,7 +356,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s) * back there or track user information then we can * only use the space before that information. */ - if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) + if ((s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) || slub_cookie) return s->inuse; /* * Else we can use all the padding etc for the allocation @@ -439,6 +495,22 @@ static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map) set_bit(slab_index(p, s, addr), map); } +static inline int size_from_object(struct kmem_cache *s) +{ + if (s->flags & SLAB_RED_ZONE) + return s->size - s->red_left_pad; + + return s->size; +} + +static inline void *restore_red_left(struct kmem_cache *s, void *p) +{ + if (s->flags & SLAB_RED_ZONE) + p -= s->red_left_pad; + + return p; +} + /* * Debug settings: */ @@ -466,9 +538,9 @@ static struct track *get_track(struct kmem_cache *s, void *object, struct track *p; if (s->offset) - p = object + s->offset + sizeof(void *); + p = object + s->offset + sizeof(void *) + sizeof(void *) * slub_cookie; else - p = object + s->inuse; + p = object + s->inuse + sizeof(void *) * slub_cookie; return p + alloc; } @@ -589,7 +661,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) printk(KERN_ERR "INFO: Object 0x%p @offset=%tu fp=0x%p\n\n", p, p - addr, get_freepointer(s, p)); - if (p > addr + 16) + if (s->flags & SLAB_RED_ZONE) + print_section("Redzone ", p - s->red_left_pad, s->red_left_pad); + else if (p > addr + 16) print_section("Bytes b4 ", p - 16, 16); print_section("Object ", p, min_t(unsigned long, s->object_size, @@ -603,6 +677,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) else off = s->inuse; + if (slub_cookie) + off += sizeof(void *); + if (s->flags & SLAB_STORE_USER) off += 2 * sizeof(struct track); @@ -648,6 +725,9 @@ static void init_object(struct kmem_cache *s, void *object, u8 val) { u8 *p = object; + if (s->flags & SLAB_RED_ZONE) + memset(p - s->red_left_pad, val, s->red_left_pad); + if (s->flags & __OBJECT_POISON) { memset(p, POISON_FREE, s->object_size - 1); p[s->object_size - 1] = POISON_END; @@ -735,6 +815,9 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) /* Freepointer is placed after the object. */ off += sizeof(void *); + if (slub_cookie) + off += sizeof(void *); + if (s->flags & SLAB_STORE_USER) /* We also have user information there */ off += 2 * sizeof(struct track); @@ -785,6 +868,10 @@ static int check_object(struct kmem_cache *s, struct page *page, u8 *endobject = object + s->object_size; if (s->flags & SLAB_RED_ZONE) { + if (!check_bytes_and_report(s, page, object, "Redzone", + object - s->red_left_pad, val, s->red_left_pad)) + return 0; + if (!check_bytes_and_report(s, page, object, "Redzone", endobject, val, s->inuse - s->object_size)) return 0; @@ -1350,6 +1437,7 @@ static void setup_object(struct kmem_cache *s, struct page *page, void *object) { setup_object_debug(s, page, object); + set_cookie(s, object, s->random_inactive); if (unlikely(s->ctor)) s->ctor(object); } @@ -1391,7 +1479,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) setup_object(s, page, last); set_freepointer(s, last, NULL); - page->freelist = start; + page->freelist = fixup_red_left(s, start); page->inuse = page->objects; page->frozen = 1; out: @@ -2402,11 +2490,21 @@ redo: stat(s, ALLOC_FASTPATH); } + if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) && !s->ctor && object) { + size_t offset = s->offset ? 0 : sizeof(void *); + BUG_ON(memchr_inv((void *)object + offset, 0, s->object_size - offset)); + } + if (unlikely(gfpflags & __GFP_ZERO) && object) memset(object, 0, s->object_size); slab_post_alloc_hook(s, gfpflags, object); + if (object) { + check_cookie(s, object, s->random_inactive); + set_cookie(s, object, s->random_active); + } + return object; } @@ -2608,6 +2706,16 @@ static __always_inline void slab_free(struct kmem_cache *s, slab_free_hook(s, x); + check_cookie(s, object, s->random_active); + set_cookie(s, object, s->random_inactive); + + if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON))) { + size_t offset = s->offset ? 0 : sizeof(void *); + memset(x + offset, 0, s->object_size - offset); + if (s->ctor) + s->ctor(x); + } + redo: /* * Determine the currently cpus per cpu slab. @@ -2675,7 +2783,7 @@ static int slub_min_objects; * Merge control. If this is set then no merging of slab caches will occur. * (Could be removed. This was introduced to pacify the merge skeptics.) */ -static int slub_nomerge; +static int slub_nomerge = 1; /* * Calculate the order of allocation given an slab object size. @@ -2852,6 +2960,7 @@ static void early_kmem_cache_node_alloc(int node) init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); init_tracking(kmem_cache_node, n); #endif + set_cookie(kmem_cache_node, n, kmem_cache_node->random_active); init_kmem_cache_node(n); inc_slabs_node(kmem_cache_node, node, page->objects); @@ -2965,6 +3074,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) size += sizeof(void *); } + if (slub_cookie) + size += sizeof(void *); + #ifdef CONFIG_SLUB_DEBUG if (flags & SLAB_STORE_USER) /* @@ -2973,7 +3085,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) */ size += 2 * sizeof(struct track); - if (flags & SLAB_RED_ZONE) + if (flags & SLAB_RED_ZONE) { /* * Add some empty padding so that we can catch * overwrites from earlier objects rather than let @@ -2982,6 +3094,11 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) * of the object. */ size += sizeof(void *); + + s->red_left_pad = sizeof(void *); + s->red_left_pad = ALIGN(s->red_left_pad, s->align); + size += s->red_left_pad; + } #endif /* @@ -3297,6 +3414,46 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) EXPORT_SYMBOL(__kmalloc_node); #endif +#ifdef CONFIG_HARDENED_USERCOPY +/* + * Rejects objects that are incorrectly sized. + * + * Returns NULL if check passes, otherwise const char * to name of cache + * to indicate an error. + */ +const char *__check_heap_object(const void *ptr, unsigned long n, + struct page *page) +{ + struct kmem_cache *s; + unsigned long offset; + size_t object_size; + + /* Find object and usable object size. */ + s = page->slab_cache; + object_size = slab_ksize(s); + + /* Reject impossible pointers. */ + if (ptr < page_address(page)) + return s->name; + + /* Find offset within object. */ + offset = (ptr - page_address(page)) % s->size; + + /* Adjust for redzone and reject if within the redzone. */ + if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) { + if (offset < s->red_left_pad) + return s->name; + offset -= s->red_left_pad; + } + + /* Allow address range falling entirely within object size. */ + if (offset <= object_size && n <= object_size - offset) + return NULL; + + return s->name; +} +#endif /* CONFIG_HARDENED_USERCOPY */ + size_t ksize(const void *object) { struct page *page; @@ -3307,7 +3464,7 @@ size_t ksize(const void *object) page = virt_to_head_page(object); if (unlikely(!PageSlab(page))) { - WARN_ON(!PageCompound(page)); + BUG_ON(!PageCompound(page)); return PAGE_SIZE << compound_order(page); } @@ -3761,6 +3918,10 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) if (err) kmem_cache_close(s); + s->random = get_random_long(); + s->random_active = get_random_long(); + s->random_inactive = get_random_long(); + return err; } diff --git a/mm/usercopy.c b/mm/usercopy.c new file mode 100644 index 0000000000000000000000000000000000000000..a6a0111cfba9100f4bdc0a8199abd5e24259f7cc --- /dev/null +++ b/mm/usercopy.c @@ -0,0 +1,298 @@ +/* + * This implements the various checks for CONFIG_HARDENED_USERCOPY*, + * which are designed to protect kernel memory from needless exposure + * and overwrite under many unintended conditions. This code is based + * on PAX_USERCOPY, which is: + * + * Copyright (C) 2001-2016 PaX Team, Bradley Spengler, Open Source + * Security Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +/* + * Checks if a given pointer and length is contained by the current + * stack frame (if possible). + * + * Returns: + * NOT_STACK: not at all on the stack + * GOOD_FRAME: fully within a valid stack frame + * GOOD_STACK: fully on the stack (when can't do frame-checking) + * BAD_STACK: error condition (invalid stack position or bad stack frame) + */ +static noinline int check_stack_object(const void *obj, unsigned long len) +{ + const void * const stack = task_stack_page(current); + const void * const stackend = stack + THREAD_SIZE; + int ret; + + /* Object is not on the stack at all. */ + if (obj + len <= stack || stackend <= obj) + return NOT_STACK; + + /* + * Reject: object partially overlaps the stack (passing the + * the check above means at least one end is within the stack, + * so if this check fails, the other end is outside the stack). + */ + if (obj < stack || stackend < obj + len) + return BAD_STACK; + + /* Check if object is safely within a valid frame. */ + ret = arch_within_stack_frames(stack, stackend, obj, len); + if (ret) + return ret; + + return GOOD_STACK; +} + +static void report_usercopy(const void *ptr, unsigned long len, + bool to_user, const char *type) +{ + pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n", + to_user ? "exposure" : "overwrite", + to_user ? "from" : "to", ptr, type ? : "unknown", len); + /* + * For greater effect, it would be nice to do do_group_exit(), + * but BUG() actually hooks all the lock-breaking and per-arch + * Oops code, so that is used here instead. + */ + BUG(); +} + +/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */ +static bool overlaps(const void *ptr, unsigned long n, unsigned long low, + unsigned long high) +{ + unsigned long check_low = (uintptr_t)ptr; + unsigned long check_high = check_low + n; + + /* Does not overlap if entirely above or entirely below. */ + if (check_low >= high || check_high <= low) + return false; + + return true; +} + +/* Is this address range in the kernel text area? */ +static inline const char *check_kernel_text_object(const void *ptr, + unsigned long n) +{ + unsigned long textlow = (unsigned long)_stext; + unsigned long texthigh = (unsigned long)_etext; + unsigned long textlow_linear, texthigh_linear; + + if (overlaps(ptr, n, textlow, texthigh)) + return ""; + + /* + * Some architectures have virtual memory mappings with a secondary + * mapping of the kernel text, i.e. there is more than one virtual + * kernel address that points to the kernel image. It is usually + * when there is a separate linear physical memory mapping, in that + * __pa() is not just the reverse of __va(). This can be detected + * and checked: + */ + textlow_linear = (unsigned long)__va(__pa(textlow)); + /* No different mapping: we're done. */ + if (textlow_linear == textlow) + return NULL; + + /* Check the secondary mapping... */ + texthigh_linear = (unsigned long)__va(__pa(texthigh)); + if (overlaps(ptr, n, textlow_linear, texthigh_linear)) + return ""; + + return NULL; +} + +static inline const char *check_bogus_address(const void *ptr, unsigned long n) +{ + /* Reject if object wraps past end of memory. */ + if (ptr + n < ptr) + return ""; + + /* Reject if NULL or ZERO-allocation. */ + if (ZERO_OR_NULL_PTR(ptr)) + return ""; + + return NULL; +} + +/* Checks for allocs that are marked in some way as spanning multiple pages. */ +static inline const char *check_page_span(const void *ptr, unsigned long n, + struct page *page, bool to_user) +{ +#ifdef CONFIG_HARDENED_USERCOPY_PAGESPAN + const void *end = ptr + n - 1; + struct page *endpage; + bool is_reserved, is_cma; + + /* + * Sometimes the kernel data regions are not marked Reserved (see + * check below). And sometimes [_sdata,_edata) does not cover + * rodata and/or bss, so check each range explicitly. + */ + + /* Allow reads of kernel rodata region (if not marked as Reserved). */ + if (ptr >= (const void *)__start_rodata && + end <= (const void *)__end_rodata) { + if (!to_user) + return ""; + return NULL; + } + + /* Allow kernel data region (if not marked as Reserved). */ + if (ptr >= (const void *)_sdata && end <= (const void *)_edata) + return NULL; + + /* Allow kernel bss region (if not marked as Reserved). */ + if (ptr >= (const void *)__bss_start && + end <= (const void *)__bss_stop) + return NULL; + + /* Is the object wholly within one base page? */ + if (likely(((unsigned long)ptr & (unsigned long)PAGE_MASK) == + ((unsigned long)end & (unsigned long)PAGE_MASK))) + return NULL; + + /* Allow if fully inside the same compound (__GFP_COMP) page. */ + endpage = virt_to_head_page(end); + if (likely(endpage == page)) + return NULL; + + /* + * Reject if range is entirely either Reserved (i.e. special or + * device memory), or CMA. Otherwise, reject since the object spans + * several independently allocated pages. + */ + is_reserved = PageReserved(page); + is_cma = is_migrate_cma_page(page); + if (!is_reserved && !is_cma) + return ""; + + for (ptr += PAGE_SIZE; ptr <= end; ptr += PAGE_SIZE) { + page = virt_to_head_page(ptr); + if (is_reserved && !PageReserved(page)) + return ""; + if (is_cma && !is_migrate_cma_page(page)) + return ""; + } +#endif + + return NULL; +} + +static inline const char *check_heap_object(const void *ptr, unsigned long n, + bool to_user) +{ + struct page *page; + + /* + * Some architectures (arm64) return true for virt_addr_valid() on + * vmalloced addresses. Work around this by checking for vmalloc + * first. + */ + if (is_vmalloc_addr(ptr)) + return NULL; + + if (!virt_addr_valid(ptr)) + return NULL; + + page = virt_to_head_page(ptr); + + /* Check slab allocator for flags and size. */ + if (PageSlab(page)) + return __check_heap_object(ptr, n, page); + + /* Verify object does not incorrectly span multiple pages. */ + return check_page_span(ptr, n, page, to_user); +} + +static struct static_key bypass_usercopy_checks = STATIC_KEY_INIT_FALSE; + +/* + * Validates that the given object is: + * - not bogus address + * - known-safe heap or stack object + * - not in kernel text + */ +void __check_object_size(const void *ptr, unsigned long n, bool to_user) +{ + const char *err; + + if (static_key_enabled(&bypass_usercopy_checks)) + return; + + /* Skip all tests if size is zero. */ + if (!n) + return; + + /* Check for invalid addresses. */ + err = check_bogus_address(ptr, n); + if (err) + goto report; + + /* Check for bad heap object. */ + err = check_heap_object(ptr, n, to_user); + if (err) + goto report; + + /* Check for bad stack object. */ + switch (check_stack_object(ptr, n)) { + case NOT_STACK: + /* Object is not touching the current process stack. */ + break; + case GOOD_FRAME: + case GOOD_STACK: + /* + * Object is either in the correct frame (when it + * is possible to check) or just generally on the + * process stack (when frame checking not available). + */ + return; + default: + err = ""; + goto report; + } + + /* Check for object in kernel to avoid text exposure. */ + err = check_kernel_text_object(ptr, n); + if (!err) + return; + +report: + report_usercopy(ptr, n, to_user, err); +} +EXPORT_SYMBOL(__check_object_size); + + +static bool enable_checks __initdata = true; + +static int __init parse_hardened_usercopy(char *str) +{ + return strtobool(str, &enable_checks); +} + +__setup("hardened_usercopy=", parse_hardened_usercopy); + +static int __init set_hardened_usercopy(void) +{ + if (enable_checks == false) + static_key_slow_inc(&bypass_usercopy_checks); + return 1; +} + +late_initcall(set_hardened_usercopy); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 17f33a62f6db559824d9dc1b3973acb779fa9162..7d4d5ac4002cf39016b0263c16117620af063e28 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -212,6 +212,9 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, struct a2mp_info_req req; found = true; + + memset(&req, 0, sizeof(req)); + req.id = cl->id; a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr), sizeof(req), &req); @@ -281,6 +284,8 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, if (!hdev || hdev->dev_type != HCI_AMP) { struct a2mp_info_rsp rsp; + memset(&rsp, 0, sizeof(rsp)); + rsp.id = req->id; rsp.status = A2MP_STATUS_INVALID_CTRL_ID; @@ -320,6 +325,8 @@ static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb, if (!ctrl) return -ENOMEM; + memset(&req, 0, sizeof(req)); + req.id = rsp->id; a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req), &req); @@ -348,6 +355,8 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb, struct a2mp_amp_assoc_rsp rsp; rsp.id = req->id; + memset(&rsp, 0, sizeof(rsp)); + if (tmp) { rsp.status = A2MP_STATUS_COLLISION_OCCURED; amp_mgr_put(tmp); @@ -447,6 +456,8 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id); + memset(&rsp, 0, sizeof(rsp)); + rsp.local_id = req->remote_id; rsp.remote_id = req->local_id; @@ -525,6 +536,8 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id); + memset(&rsp, 0, sizeof(rsp)); + rsp.local_id = req->remote_id; rsp.remote_id = req->local_id; rsp.status = A2MP_STATUS_SUCCESS; @@ -646,7 +659,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) if (err) { struct a2mp_cmd_rej rej; - rej.reason = __constant_cpu_to_le16(0); + memset(&rej, 0, sizeof(rej)); + + rej.reason = __constant_cpu_to_le16(0); hdr = (void *) skb->data; BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); @@ -868,6 +883,8 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev) BT_DBG("%s mgr %p", hdev->name, mgr); + memset(&rsp, 0, sizeof(rsp)); + rsp.id = hdev->id; rsp.status = A2MP_STATUS_INVALID_CTRL_ID; @@ -965,6 +982,8 @@ void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status) if (!mgr) return; + memset(&rsp, 0, sizeof(rsp)); + hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT); if (!hs_hcon) { rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; @@ -997,6 +1016,8 @@ void a2mp_discover_amp(struct l2cap_chan *chan) mgr->bredr_chan = chan; + memset(&req, 0, sizeof(req)); + req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); req.ext_feat = 0; a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req); diff --git a/net/core/dev.c b/net/core/dev.c index 85e4a9460a95ba24736449ef8f498886be0eb3d4..e6bff4f00a15d89a6d2a18271cb17ebbfff4cf06 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1043,9 +1043,8 @@ static int dev_alloc_name_ns(struct net *net, return ret; } -static int dev_get_valid_name(struct net *net, - struct net_device *dev, - const char *name) +int dev_get_valid_name(struct net *net, struct net_device *dev, + const char *name) { BUG_ON(!net); @@ -1061,6 +1060,7 @@ static int dev_get_valid_name(struct net *net, return 0; } +EXPORT_SYMBOL(dev_get_valid_name); /** * dev_change_name - change name of a device @@ -4051,9 +4051,16 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd) while (remsd) { struct softnet_data *next = remsd->rps_ipi_next; - if (cpu_online(remsd->cpu)) + if (cpu_online(remsd->cpu)) { __smp_call_function_single(remsd->cpu, &remsd->csd, 0); + } else { + pr_err("%s(), cpu was offline and IPI was not " + "delivered so clean up NAPI", __func__); + rps_lock(remsd); + remsd->backlog.state = 0; + rps_unlock(remsd); + } remsd = next; } } else @@ -4061,20 +4068,28 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd) local_irq_enable(); } +static bool sd_has_rps_ipi_waiting(struct softnet_data *sd) +{ +#ifdef CONFIG_RPS + return sd->rps_ipi_list != NULL; +#else + return false; +#endif +} + static int process_backlog(struct napi_struct *napi, int quota) { int work = 0; struct softnet_data *sd = container_of(napi, struct softnet_data, backlog); -#ifdef CONFIG_RPS /* Check if we have pending ipi, its better to send them now, * not waiting net_rx_action() end. */ - if (sd->rps_ipi_list) { + if (sd_has_rps_ipi_waiting(sd)) { local_irq_disable(); net_rps_action_and_irq_enable(sd); } -#endif + napi->weight = weight_p; local_irq_disable(); while (work < quota) { @@ -4108,7 +4123,6 @@ static int process_backlog(struct napi_struct *napi, int quota) * we can use a plain write instead of clear_bit(), * and we dont need an smp_mb() memory barrier. */ - list_del(&napi->poll_list); napi->state = 0; quota = work + qlen; @@ -4141,7 +4155,7 @@ void __napi_complete(struct napi_struct *n) BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); BUG_ON(n->gro_list); - list_del(&n->poll_list); + list_del_init(&n->poll_list); smp_mb__before_atomic(); clear_bit(NAPI_STATE_SCHED, &n->state); } @@ -4159,9 +4173,15 @@ void napi_complete(struct napi_struct *n) return; napi_gro_flush(n, false); - local_irq_save(flags); - __napi_complete(n); - local_irq_restore(flags); + + if (likely(list_empty(&n->poll_list))) { + WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state)); + } else { + /* If n->poll_list is not empty, we need to mask irqs */ + local_irq_save(flags); + __napi_complete(n); + local_irq_restore(flags); + } } EXPORT_SYMBOL(napi_complete); @@ -4210,29 +4230,28 @@ static void net_rx_action(struct softirq_action *h) struct softnet_data *sd = &__get_cpu_var(softnet_data); unsigned long time_limit = jiffies + 2; int budget = netdev_budget; + LIST_HEAD(list); + LIST_HEAD(repoll); void *have; local_irq_disable(); + list_splice_init(&sd->poll_list, &list); + local_irq_enable(); - while (!list_empty(&sd->poll_list)) { + while (!list_empty(&list)) { struct napi_struct *n; int work, weight; - /* If softirq window is exhuasted then punt. + /* If softirq window is exhausted then punt. * Allow this to run for 2 jiffies since which will allow * an average latency of 1.5/HZ. */ if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit))) goto softnet_break; - local_irq_enable(); - /* Even though interrupts have been re-enabled, this - * access is safe because interrupts can only add new - * entries to the tail of this list, and only ->poll() - * calls can remove this head entry from the list. - */ - n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list); + n = list_first_entry(&list, struct napi_struct, poll_list); + list_del_init(&n->poll_list); have = netpoll_poll_lock(n); @@ -4254,8 +4273,6 @@ static void net_rx_action(struct softirq_action *h) budget -= work; - local_irq_disable(); - /* Drivers must not modify the NAPI state if they * consume the entire weight. In such cases this code * still "owns" the NAPI instance and therefore can @@ -4263,25 +4280,34 @@ static void net_rx_action(struct softirq_action *h) */ if (unlikely(work == weight)) { if (unlikely(napi_disable_pending(n))) { - local_irq_enable(); napi_complete(n); - local_irq_disable(); } else { if (n->gro_list) { /* flush too old packets * If HZ < 1000, flush all packets. */ - local_irq_enable(); napi_gro_flush(n, HZ >= 1000); - local_irq_disable(); } - list_move_tail(&n->poll_list, &sd->poll_list); + list_add_tail(&n->poll_list, &repoll); } } netpoll_poll_unlock(have); } + + if (!sd_has_rps_ipi_waiting(sd) && + list_empty(&list) && + list_empty(&repoll)) + return; out: + local_irq_disable(); + + list_splice_tail_init(&sd->poll_list, &list); + list_splice_tail(&repoll, &list); + list_splice(&list, &sd->poll_list); + if (!list_empty(&sd->poll_list)) + __raise_softirq_irqoff(NET_RX_SOFTIRQ); + net_rps_action_and_irq_enable(sd); #ifdef CONFIG_NET_DMA @@ -4296,7 +4322,6 @@ out: softnet_break: sd->time_squeeze++; - __raise_softirq_irqoff(NET_RX_SOFTIRQ); goto out; } diff --git a/net/core/sock.c b/net/core/sock.c index e6c357f91df56e9c174ebaef4cd370bb629de01f..36dde6e077af1304c3fa744d46951b76f2f7b10d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -98,6 +98,7 @@ #include #include +#include #include #include #include @@ -1969,20 +1970,21 @@ static void __release_sock(struct sock *sk) * sk_wait_data - wait for data to arrive at sk_receive_queue * @sk: sock to wait on * @timeo: for how long + * @skb: last skb seen on sk_receive_queue * * Now socket state including sk->sk_err is changed only under lock, * hence we may omit checks after joining wait queue. * We check receive queue before schedule() only as optimization; * it is very likely that release_sock() added new data. */ -int sk_wait_data(struct sock *sk, long *timeo) +int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb) { int rc; DEFINE_WAIT(wait); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue)); + rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb); clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); finish_wait(sk_sleep(sk), &wait); return rc; @@ -2486,6 +2488,52 @@ void sock_enable_timestamp(struct sock *sk, int flag) } } +int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, + int level, int type) +{ + struct sock_exterr_skb *serr; + struct sk_buff *skb, *skb2; + int copied, err; + + err = -EAGAIN; + skb = skb_dequeue(&sk->sk_error_queue); + if (skb == NULL) + goto out; + + copied = skb->len; + if (copied > len) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto out_free_skb; + + sock_recv_timestamp(msg, sk, skb); + + serr = SKB_EXT_ERR(skb); + put_cmsg(msg, level, type, sizeof(serr->ee), &serr->ee); + + msg->msg_flags |= MSG_ERRQUEUE; + err = copied; + + /* Reset and regenerate socket error */ + spin_lock_bh(&sk->sk_error_queue.lock); + sk->sk_err = 0; + if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { + sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; + spin_unlock_bh(&sk->sk_error_queue.lock); + sk->sk_error_report(sk); + } else + spin_unlock_bh(&sk->sk_error_queue.lock); + +out_free_skb: + kfree_skb(skb); +out: + return err; +} +EXPORT_SYMBOL(sock_recv_errqueue); + /* * Get a socket option on an socket. * diff --git a/net/core/sockev_nlmcast.c b/net/core/sockev_nlmcast.c index 749ffb81c87c807b396037a2e34bb1d9dc2da79f..8e0b47816e674c3c0249bc4d262f1085956eebee 100644 --- a/net/core/sockev_nlmcast.c +++ b/net/core/sockev_nlmcast.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015,2018, The Linux Foundation. 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 and @@ -36,6 +36,8 @@ static struct netlink_kernel_cfg nlcfg = { static void _sockev_event(unsigned long event, __u8 *evstr, int buflen) { + memset(evstr, 0, buflen); + switch (event) { case SOCKEV_SOCKET: strlcpy(evstr, "SOCKEV_SOCKET", buflen); diff --git a/net/core/utils.c b/net/core/utils.c index 3c7f5b51b979c88a3dc1d0bc9cf6c44f2e74d182..2e2cd88e1d9ac9b3cfe982541d278308b6f163d4 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -360,3 +360,52 @@ int mac_pton(const char *s, u8 *mac) return 1; } EXPORT_SYMBOL(mac_pton); + +struct __net_random_once_work { + struct work_struct work; + struct static_key *key; +}; + +static void __net_random_once_deferred(struct work_struct *w) +{ + struct __net_random_once_work *work = + container_of(w, struct __net_random_once_work, work); + BUG_ON(!static_key_enabled(work->key)); + static_key_slow_dec(work->key); + kfree(work); +} + +static void __net_random_once_disable_jump(struct static_key *key) +{ + struct __net_random_once_work *w; + + w = kmalloc(sizeof(*w), GFP_ATOMIC); + if (!w) + return; + + INIT_WORK(&w->work, __net_random_once_deferred); + w->key = key; + schedule_work(&w->work); +} + +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *once_key) +{ + static DEFINE_SPINLOCK(lock); + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + if (*done) { + spin_unlock_irqrestore(&lock, flags); + return false; + } + + get_random_bytes(buf, nbytes); + *done = true; + spin_unlock_irqrestore(&lock, flags); + + __net_random_once_disable_jump(once_key); + + return true; +} +EXPORT_SYMBOL(__net_get_random_once); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index cb55fb912401852a4de96b8176d0c398d02254b7..2e08919e36c68ce77df8d01e866cedf2e8a96c61 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -888,7 +888,7 @@ verify_sock_status: break; } - sk_wait_data(sk, &timeo); + sk_wait_data(sk, &timeo, NULL); continue; found_ok_skb: if (len > skb->len) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ee3c309ef4a2213ce4ac47874119cc2a18f87794..bffeea0927f357f0e1600e02cb7e05f3ea28c304 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1324,7 +1324,7 @@ skip: static bool inetdev_valid_mtu(unsigned int mtu) { - return mtu >= 68; + return mtu >= IPV4_MIN_MTU; } static void inetdev_send_gratuitous_arp(struct net_device *dev, diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5af8781b65e13f49c0f3ce90bcfa695cf83756a6..59e63dcb80dadf6987bd18063c06b6ce9fdbf14b 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -364,6 +364,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) fl4.daddr = daddr; fl4.saddr = saddr; fl4.flowi4_mark = mark; + fl4.flowi4_uid = sock_net_uid(net, NULL); fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); fl4.flowi4_proto = IPPROTO_ICMP; security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); @@ -395,6 +396,7 @@ static struct rtable *icmp_route_lookup(struct net *net, param->replyopts.opt.opt.faddr : iph->saddr); fl4->saddr = saddr; fl4->flowi4_mark = mark; + fl4->flowi4_uid = sock_net_uid(net, NULL); fl4->flowi4_tos = RT_TOS(tos); fl4->flowi4_proto = IPPROTO_ICMP; fl4->fl4_icmp_type = type; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 4572ee7c71f4afe796033a3024c8fe3e5d4c7cbc..cf66f3fe83ab946b974537b3841d891bcb9d2b31 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -381,16 +381,17 @@ static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) } static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, - int type, struct igmpv3_grec **ppgr) + int type, struct igmpv3_grec **ppgr, unsigned int mtu) { struct net_device *dev = pmc->interface->dev; struct igmpv3_report *pih; struct igmpv3_grec *pgr; - if (!skb) - skb = igmpv3_newpack(dev, dev->mtu); - if (!skb) - return NULL; + if (!skb) { + skb = igmpv3_newpack(dev, mtu); + if (!skb) + return NULL; + } pgr = (struct igmpv3_grec *)skb_put(skb, sizeof(struct igmpv3_grec)); pgr->grec_type = type; pgr->grec_auxwords = 0; @@ -413,10 +414,15 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, struct igmpv3_grec *pgr = NULL; struct ip_sf_list *psf, *psf_next, *psf_prev, **psf_list; int scount, stotal, first, isquery, truncate; + unsigned int mtu; if (pmc->multiaddr == IGMP_ALL_HOSTS) return skb; + mtu = READ_ONCE(dev->mtu); + if (mtu < IPV4_MIN_MTU) + return skb; + isquery = type == IGMPV3_MODE_IS_INCLUDE || type == IGMPV3_MODE_IS_EXCLUDE; truncate = type == IGMPV3_MODE_IS_EXCLUDE || @@ -437,7 +443,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { if (skb) igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); + skb = igmpv3_newpack(dev, mtu); } } first = 1; @@ -464,12 +470,12 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, pgr->grec_nsrcs = htons(scount); if (skb) igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); + skb = igmpv3_newpack(dev, mtu); first = 1; scount = 0; } if (first) { - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); first = 0; } if (!skb) @@ -503,7 +509,7 @@ empty_source: igmpv3_sendpack(skb); skb = NULL; /* add_grhead will get a new one */ } - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); } } if (pgr) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index d0025a2426301223103052ac2072cb6ca7246fe6..912cb4dedfe59dbf2d8c7db877965961d1fbdd83 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -429,7 +429,8 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, sk->sk_protocol, flags, (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, - ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport, + sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) @@ -465,7 +466,8 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, - ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport, + sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7ad943e475b6ff63db37c25e4a6a463cfde72477..681a91e6b12623693dbaab6c61587ab8dea4c5d0 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -985,7 +985,8 @@ alloc_new_skb: if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; @@ -1494,7 +1495,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol, ip_reply_arg_flowi_flags(arg), daddr, saddr, - tcp_hdr(skb)->source, tcp_hdr(skb)->dest); + tcp_hdr(skb)->source, tcp_hdr(skb)->dest, + arg->uid); security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3d009e17416656159f13144bdec9ca18512165a8..265fb8731578cdd0ca7513498c59fcfc609a1f9d 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1066,11 +1066,8 @@ int ip_setsockopt(struct sock *sk, int level, if (err == -ENOPROTOOPT && optname != IP_HDRINCL && optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY && - !ip_mroute_opt(optname)) { - lock_sock(sk); + !ip_mroute_opt(optname)) err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); - release_sock(sk); - } #endif return err; } @@ -1095,12 +1092,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, if (err == -ENOPROTOOPT && optname != IP_HDRINCL && optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY && - !ip_mroute_opt(optname)) { - lock_sock(sk); - err = compat_nf_setsockopt(sk, PF_INET, optname, - optval, optlen); - release_sock(sk); - } + !ip_mroute_opt(optname)) + err = compat_nf_setsockopt(sk, PF_INET, optname, optval, + optlen); #endif return err; } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 84aa69caee59486e3dffa0e0c8447a0c278ab0ed..425f4e44f812844d55c197dae8f25b656e6f41bf 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -379,8 +379,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev) dev->needed_headroom = t_hlen + hlen; mtu -= (dev->hard_header_len + t_hlen); - if (mtu < 68) - mtu = 68; + if (mtu < IPV4_MIN_MTU) + mtu = IPV4_MIN_MTU; return mtu; } diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index efa1138fa523be1ed228b66accbfa9ed75920265..3da772ae8808662b37e0e12ff5cbb4ac1aed6b27 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -143,8 +143,6 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */ __be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ -__be32 ic_dev_xid; /* Device under configuration */ - /* vendor class identifier */ static char vendor_class_identifier[253] __initdata; @@ -264,7 +262,8 @@ static int __init ic_open_devs(void) /* wait for a carrier on at least one device */ start = jiffies; next_msg = start + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12); - while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) { + while (time_before(jiffies, start + + msecs_to_jiffies(CONF_CARRIER_TIMEOUT))) { int wait, elapsed; for_each_netdev(&init_net, dev) @@ -273,7 +272,7 @@ static int __init ic_open_devs(void) msleep(1); - if time_before(jiffies, next_msg) + if (time_before(jiffies, next_msg)) continue; elapsed = jiffies_to_msecs(jiffies - start); @@ -654,6 +653,7 @@ static struct packet_type bootp_packet_type __initdata = { .func = ic_bootp_recv, }; +static __be32 ic_dev_xid; /* Device under configuration */ /* * Initialize DHCP/BOOTP extension fields in the request. @@ -772,6 +772,11 @@ static void __init ic_bootp_init_ext(u8 *e) */ static inline void __init ic_bootp_init(void) { + /* Re-initialise all name servers to NONE, in case any were set via the + * "ip=" or "nfsaddrs=" kernel command line parameters: any IP addresses + * specified there will already have been decoded but are no longer + * needed + */ ic_nameservers_predef(); dev_add_pack(&bootp_packet_type); @@ -1218,10 +1223,10 @@ static int __init ic_dynamic(void) get_random_bytes(&timeout, sizeof(timeout)); timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM); for (;;) { +#ifdef IPCONFIG_BOOTP /* Track the device we are configuring */ ic_dev_xid = d->xid; -#ifdef IPCONFIG_BOOTP if (do_bootp && (d->able & IC_BOOTP)) ic_bootp_send_if(d, jiffies - start_jiffies); #endif @@ -1404,6 +1409,13 @@ static int __init ip_auto_config(void) int err; unsigned int i; + /* Initialise all name servers to NONE (but only if the "ip=" or + * "nfsaddrs=" kernel command line parameters weren't decoded, otherwise + * we'll overwrite the IP addresses specified there) + */ + if (ic_set_manually == 0) + ic_nameservers_predef(); + #ifdef CONFIG_PROC_FS proc_create("pnp", S_IRUGO, init_net.proc_net, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ @@ -1605,6 +1617,7 @@ static int __init ip_auto_config_setup(char *addrs) return 1; } + /* Initialise all name servers to NONE */ ic_nameservers_predef(); /* Parse string for static IP assignment. */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 71f6b12c47fb95d182ff21431a9c2d3349b5053d..dc593bd4fcbf5a5cfdcf807a618808b9d49c3bd6 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -71,7 +71,8 @@ config IP_NF_MATCH_ECN config IP_NF_MATCH_RPFILTER tristate '"rpfilter" reverse path filter match support' - depends on NETFILTER_ADVANCED && (IP_NF_MANGLE || IP_NF_RAW) + depends on NETFILTER_ADVANCED + depends on IP_NF_MANGLE || IP_NF_RAW ---help--- This option allows you to match packets whose replies would go out via the interface the packet came in. diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 3217acd4e33bbe1a35d4661e10b5bf7b533ba764..c6bc0a2ea0b461d7cb73de8ded2d2395494f3190 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1312,6 +1312,8 @@ static int translate_compat_table(struct xt_table_info **pinfo, if (!newinfo) goto out_unlock; + memset(newinfo->entries, 0, size); + newinfo->number = compatr->num_entries; for (i = 0; i < NF_ARP_NUMHOOKS; i++) { newinfo->hook_entry[i] = compatr->hook_entry[i]; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index fdca7ed200e26a87278021597ef47e9aeef87074..200bc2777ee691095f4bc912ccf524c2240f2c58 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1584,6 +1584,8 @@ translate_compat_table(struct net *net, if (!newinfo) goto out_unlock; + memset(newinfo->entries, 0, size); + newinfo->number = compatr->num_entries; for (i = 0; i < NF_INET_NUMHOOKS; i++) { newinfo->hook_entry[i] = compatr->hook_entry[i]; diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 0b732efd32e20aa8e22e6c9bd5aa4edfb7e5516d..47ee87fcfc1fc2ecd9b3d353df92254748e51018 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -353,7 +353,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) struct ipt_clusterip_tgt_info *cipinfo = par->targinfo; const struct ipt_entry *e = par->entryinfo; struct clusterip_config *config; - int ret; + int ret, i; if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && @@ -367,8 +367,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) pr_info("Please specify destination IP\n"); return -EINVAL; } - - /* FIXME: further sanity checks */ + if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) { + pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes); + return -EINVAL; + } + for (i = 0; i < cipinfo->num_local_nodes; i++) { + if (cipinfo->local_nodes[i] - 1 >= + sizeof(config->local_nodes) * 8) { + pr_info("bad local_nodes[%d] %u\n", + i, cipinfo->local_nodes[i]); + return -EINVAL; + } + } config = clusterip_config_find_get(e->ip.dst.s_addr, 1); if (!config) { diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 567d84168bd2e6e878b9a85733a649e3845eabdf..6d3ebba565d2e7f6225a16c70edd06df4eb54ca5 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -272,15 +272,19 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) struct nf_conntrack_tuple tuple; memset(&tuple, 0, sizeof(tuple)); + + lock_sock(sk); tuple.src.u3.ip = inet->inet_rcv_saddr; tuple.src.u.tcp.port = inet->inet_sport; tuple.dst.u3.ip = inet->inet_daddr; tuple.dst.u.tcp.port = inet->inet_dport; tuple.src.l3num = PF_INET; tuple.dst.protonum = sk->sk_protocol; + release_sock(sk); /* We only do TCP and SCTP at the moment: is there a better way? */ - if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) { + if (tuple.dst.protonum != IPPROTO_TCP && + tuple.dst.protonum != IPPROTO_SCTP) { pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); return -ENOPROTOOPT; } diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 1e82bdb0f07e6a3247ae4a2c1b9758d3af29aa79..6860875c929fb983998c760d1755b9943b4a860c 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -1261,16 +1261,6 @@ static const struct nf_conntrack_expect_policy snmp_exp_policy = { .timeout = 180, }; -static struct nf_conntrack_helper snmp_helper __read_mostly = { - .me = THIS_MODULE, - .help = help, - .expect_policy = &snmp_exp_policy, - .name = "snmp", - .tuple.src.l3num = AF_INET, - .tuple.src.u.udp.port = cpu_to_be16(SNMP_PORT), - .tuple.dst.protonum = IPPROTO_UDP, -}; - static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { .me = THIS_MODULE, .help = help, @@ -1289,17 +1279,10 @@ static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { static int __init nf_nat_snmp_basic_init(void) { - int ret = 0; - BUG_ON(nf_nat_snmp_hook != NULL); RCU_INIT_POINTER(nf_nat_snmp_hook, help); - ret = nf_conntrack_helper_register(&snmp_trap_helper); - if (ret < 0) { - nf_conntrack_helper_unregister(&snmp_helper); - return ret; - } - return ret; + return nf_conntrack_helper_register(&snmp_trap_helper); } static void __exit nf_nat_snmp_basic_fini(void) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 547a3d63f3227a60e8840b7e592a05032c9da3b8..a2007c06f81e74a4ed8a21c9bbbc5b9656e74bea 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -790,7 +790,8 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk), faddr, saddr, 0, 0); + inet_sk_flowi_flags(sk), faddr, saddr, 0, 0, + sk->sk_uid); security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index a2e361c956b753b0f1c0a0b5382b42baab7973ef..7e1588ccf60d5de98c16e302f8c71ffe137a94c4 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -576,7 +576,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), - daddr, saddr, 0, 0); + daddr, saddr, 0, 0, sk->sk_uid); if (!inet->hdrincl) { err = raw_probe_proto_opt(&fl4, msg); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c564dcf2c80cbe823af74d0b593ee6dd0c63029d..2d33a4f6ae59e9dd834140fab3d229d01802e434 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -124,9 +124,11 @@ static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); static int ip_rt_error_cost __read_mostly = HZ; static int ip_rt_error_burst __read_mostly = 5 * HZ; static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; -static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; +static u32 ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; +static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; + /* * Interface to generic destination cache. */ @@ -515,7 +517,8 @@ void __ip_select_ident(struct iphdr *iph, int segs) } EXPORT_SYMBOL(__ip_select_ident); -static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, +static void __build_flow_key(const struct net *net, struct flowi4 *fl4, + const struct sock *sk, const struct iphdr *iph, int oif, u8 tos, u8 prot, u32 mark, int flow_flags) @@ -531,19 +534,21 @@ static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, flowi4_init_output(fl4, oif, mark, tos, RT_SCOPE_UNIVERSE, prot, flow_flags, - iph->daddr, iph->saddr, 0, 0); + iph->daddr, iph->saddr, 0, 0, + sock_net_uid(net, sk)); } static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, const struct sock *sk) { + const struct net *net = dev_net(skb->dev); const struct iphdr *iph = ip_hdr(skb); int oif = skb->dev->ifindex; u8 tos = RT_TOS(iph->tos); u8 prot = iph->protocol; u32 mark = skb->mark; - __build_flow_key(fl4, sk, iph, oif, tos, prot, mark, 0); + __build_flow_key(net, fl4, sk, iph, oif, tos, prot, mark, 0); } static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) @@ -560,7 +565,7 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk), - daddr, inet->inet_saddr, 0, 0); + daddr, inet->inet_saddr, 0, 0, sk->sk_uid); rcu_read_unlock(); } @@ -640,10 +645,9 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, if (fnhe) { if (gw) fnhe->fnhe_gw = gw; - if (pmtu) { + if (pmtu) fnhe->fnhe_pmtu = pmtu; - fnhe->fnhe_expires = expires; - } + fnhe->fnhe_expires = expires; } else { if (depth > FNHE_RECLAIM_DEPTH) fnhe = fnhe_oldest(hash); @@ -755,6 +759,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf struct rtable *rt; struct flowi4 fl4; const struct iphdr *iph = (const struct iphdr *) skb->data; + struct net *net = dev_net(skb->dev); int oif = skb->dev->ifindex; u8 tos = RT_TOS(iph->tos); u8 prot = iph->protocol; @@ -762,7 +767,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf rt = (struct rtable *) dst; - __build_flow_key(&fl4, sk, iph, oif, tos, prot, mark, 0); + __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0); __ip_do_redirect(rt, skb, &fl4, true); } @@ -980,7 +985,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, if (!mark) mark = IP4_REPLY_MARK(net, skb->mark); - __build_flow_key(&fl4, NULL, iph, oif, + __build_flow_key(net, &fl4, NULL, iph, oif, RT_TOS(iph->tos), protocol, mark, flow_flags); rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { @@ -996,7 +1001,7 @@ static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) struct flowi4 fl4; struct rtable *rt; - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + __build_flow_key(sock_net(sk), &fl4, sk, iph, 0, 0, 0, 0, 0); if (!fl4.flowi4_mark) fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark); @@ -1015,6 +1020,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) struct rtable *rt; struct dst_entry *odst = NULL; bool new = false; + struct net *net = sock_net(sk); bh_lock_sock(sk); odst = sk_dst_get(sk); @@ -1024,7 +1030,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) goto out; } - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + __build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0); rt = (struct rtable *)odst; if (odst->obsolete && odst->ops->check(odst, 0) == NULL) { @@ -1064,7 +1070,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net, struct flowi4 fl4; struct rtable *rt; - __build_flow_key(&fl4, NULL, iph, oif, + __build_flow_key(net, &fl4, NULL, iph, oif, RT_TOS(iph->tos), protocol, mark, flow_flags); rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { @@ -1079,9 +1085,10 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk) const struct iphdr *iph = (const struct iphdr *) skb->data; struct flowi4 fl4; struct rtable *rt; + struct net *net = sock_net(sk); - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); - rt = __ip_route_output_key(sock_net(sk), &fl4); + __build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0); + rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { __ip_do_redirect(rt, skb, &fl4, false); ip_rt_put(rt); @@ -2599,7 +2606,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_min_pmtu, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &ip_min_valid_pmtu, }, { .procname = "min_adv_mss", diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 5abb45e281bea0ffdcfd14d9e017742d7b19c71a..296a0a42b2b8716942e9f9da27985e3e0bf13dec 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -353,7 +353,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP, inet_sk_flowi_flags(sk), (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, - ireq->loc_addr, th->source, th->dest); + ireq->loc_addr, th->source, th->dest, sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7192b9c25c2c24406f3bfe21d439cd924ecf2cfd..a1b3069088edc325738c19e17815772ee48b590d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -740,7 +740,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, */ if (!skb_queue_empty(&sk->sk_receive_queue)) break; - sk_wait_data(sk, &timeo); + sk_wait_data(sk, &timeo, NULL); if (signal_pending(current)) { ret = sock_intr_errno(timeo); break; @@ -1022,9 +1022,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied, size_t size) { struct tcp_sock *tp = tcp_sk(sk); + struct sockaddr *uaddr = msg->msg_name; int err, flags; - if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE)) + if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) || + (uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) && + uaddr->sa_family == AF_UNSPEC)) return -EOPNOTSUPP; if (tp->fastopen_req != NULL) return -EALREADY; /* Another Fast Open is in progress */ @@ -1037,7 +1040,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, tp->fastopen_req->size = size; flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; - err = __inet_stream_connect(sk->sk_socket, msg->msg_name, + err = __inet_stream_connect(sk->sk_socket, uaddr, msg->msg_namelen, flags); *copied = tp->fastopen_req->copied; tcp_free_fastopen_req(tp); @@ -1058,7 +1061,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, lock_sock(sk); flags = msg->msg_flags; - if (flags & MSG_FASTOPEN) { + if ((flags & MSG_FASTOPEN) && !tp->repair) { err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size); if (err == -EINPROGRESS && copied_syn > 0) goto out; @@ -1594,7 +1597,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, long timeo; struct task_struct *user_recv = NULL; bool copied_early = false; - struct sk_buff *skb; + struct sk_buff *skb, *last; u32 urg_hole = 0; lock_sock(sk); @@ -1669,7 +1672,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Next get a buffer. */ + last = skb_peek_tail(&sk->sk_receive_queue); skb_queue_walk(&sk->sk_receive_queue, skb) { + last = skb; /* Now that we have two receive queues this * shouldn't happen. */ @@ -1798,8 +1803,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Do not sleep, just process backlog. */ release_sock(sk); lock_sock(sk); - } else - sk_wait_data(sk, &timeo); + } else { + sk_wait_data(sk, &timeo, last); + } #ifdef CONFIG_NET_DMA tcp_service_net_dma(sk, false); /* Don't block */ @@ -2250,6 +2256,9 @@ adjudge_to_death: tcp_send_active_reset(sk, GFP_ATOMIC); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { + /* Not possible to send reset; just close */ + tcp_set_state(sk, TCP_CLOSE); } } @@ -2348,6 +2357,12 @@ int tcp_disconnect(struct sock *sk, int flags) WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); + if (sk->sk_frag.page) { + put_page(sk->sk_frag.page); + sk->sk_frag.page = NULL; + sk->sk_frag.offset = 0; + } + sk->sk_error_report(sk); return err; } @@ -2523,7 +2538,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, case TCP_REPAIR_QUEUE: if (!tp->repair) err = -EPERM; - else if (val < TCP_QUEUES_NR) + else if ((unsigned int)val < TCP_QUEUES_NR) tp->repair_queue = val; else err = -EINVAL; @@ -2655,8 +2670,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, #ifdef CONFIG_TCP_MD5SIG case TCP_MD5SIG: - /* Read the IP->Key mappings from userspace */ - err = tp->af_specific->md5_parse(sk, optval, optlen); + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) + err = tp->af_specific->md5_parse(sk, optval, optlen); + else + err = -EINVAL; break; #endif case TCP_USER_TIMEOUT: diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index f45e1c24244091a750f5f34ca0fe9e9038731ca5..5a2fc9903ceb0139a4e9f767a13fcf6026671347 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -17,7 +17,6 @@ #include #include - #define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation * max_cwnd = snd_cwnd * beta */ @@ -46,11 +45,10 @@ MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold"); module_param(smooth_part, int, 0644); MODULE_PARM_DESC(smooth_part, "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax"); - /* BIC TCP Parameters */ struct bictcp { u32 cnt; /* increase cwnd by 1 after ACKs */ - u32 last_max_cwnd; /* last maximum snd_cwnd */ + u32 last_max_cwnd; /* last maximum snd_cwnd */ u32 loss_cwnd; /* congestion window at last loss */ u32 last_cwnd; /* the last snd_cwnd */ u32 last_time; /* time when updated last_cwnd */ @@ -103,7 +101,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) /* binary increase */ if (cwnd < ca->last_max_cwnd) { - __u32 dist = (ca->last_max_cwnd - cwnd) + __u32 dist = (ca->last_max_cwnd - cwnd) / BICTCP_B; if (dist > max_increment) @@ -154,7 +152,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) bictcp_update(ca, tp->snd_cwnd); tcp_cong_avoid_ai(tp, ca->cnt); } - } /* @@ -177,7 +174,6 @@ static u32 bictcp_recalc_ssthresh(struct sock *sk) ca->loss_cwnd = tp->snd_cwnd; - if (tp->snd_cwnd <= low_window) return max(tp->snd_cwnd >> 1U, 2U); else @@ -188,6 +184,7 @@ static u32 bictcp_undo_cwnd(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); const struct bictcp *ca = inet_csk_ca(sk); + return max(tp->snd_cwnd, ca->loss_cwnd); } @@ -206,12 +203,12 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt) if (icsk->icsk_ca_state == TCP_CA_Open) { struct bictcp *ca = inet_csk_ca(sk); + cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT; ca->delayed_ack += cnt; } } - static struct tcp_congestion_ops bictcp __read_mostly = { .init = bictcp_init, .ssthresh = bictcp_recalc_ssthresh, diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 2ca6c080a4bc46ae59b99b203d6a89b2c76b7623..f2c6f3b552be42f5131ee4634eb121abfbe828d5 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -145,7 +145,6 @@ static int __init tcp_congestion_default(void) } late_initcall(tcp_congestion_default); - /* Build string with list of available congestion control values */ void tcp_get_available_congestion_control(char *buf, size_t maxlen) { @@ -157,7 +156,6 @@ void tcp_get_available_congestion_control(char *buf, size_t maxlen) offs += snprintf(buf + offs, maxlen - offs, "%s%s", offs == 0 ? "" : " ", ca->name); - } rcu_read_unlock(); } @@ -189,7 +187,6 @@ void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) offs += snprintf(buf + offs, maxlen - offs, "%s%s", offs == 0 ? "" : " ", ca->name); - } rcu_read_unlock(); } @@ -233,7 +230,6 @@ out: return ret; } - /* Change congestion control for socket */ int tcp_set_congestion_control(struct sock *sk, const char *name) { @@ -372,6 +368,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid); u32 tcp_reno_ssthresh(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); + return max(tp->snd_cwnd >> 1U, 2U); } EXPORT_SYMBOL_GPL(tcp_reno_ssthresh); diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 894b7cea5d7b5cfa82224841ed70f7b03803239d..24b1f9cb5ecdbc2898ce16abed6738a288a350a2 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -82,12 +82,13 @@ MODULE_PARM_DESC(hystart_ack_delta, "spacing between ack's indicating train (mse /* BIC TCP Parameters */ struct bictcp { u32 cnt; /* increase cwnd by 1 after ACKs */ - u32 last_max_cwnd; /* last maximum snd_cwnd */ + u32 last_max_cwnd; /* last maximum snd_cwnd */ u32 loss_cwnd; /* congestion window at last loss */ u32 last_cwnd; /* the last snd_cwnd */ u32 last_time; /* time when updated last_cwnd */ u32 bic_origin_point;/* origin point of bic function */ - u32 bic_K; /* time to origin point from the beginning of the current epoch */ + u32 bic_K; /* time to origin point + from the beginning of the current epoch */ u32 delay_min; /* min delay (msec << 3) */ u32 epoch_start; /* beginning of an epoch */ u32 ack_cnt; /* number of acks */ @@ -219,7 +220,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) ca->last_time = tcp_time_stamp; if (ca->epoch_start == 0) { - ca->epoch_start = tcp_time_stamp; /* record the beginning of an epoch */ + ca->epoch_start = tcp_time_stamp; /* record beginning */ ca->ack_cnt = 1; /* start counting */ ca->tcp_cwnd = cwnd; /* syn with cubic */ @@ -263,9 +264,9 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) /* c/rtt * (t-K)^3 */ delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ); - if (t < ca->bic_K) /* below origin*/ + if (t < ca->bic_K) /* below origin*/ bic_target = ca->bic_origin_point - delta; - else /* above origin*/ + else /* above origin*/ bic_target = ca->bic_origin_point + delta; /* cubic function - calc bictcp_cnt*/ @@ -285,13 +286,14 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) /* TCP Friendly */ if (tcp_friendliness) { u32 scale = beta_scale; + delta = (cwnd * scale) >> 3; while (ca->ack_cnt > delta) { /* update tcp cwnd */ ca->ack_cnt -= delta; ca->tcp_cwnd++; } - if (ca->tcp_cwnd > cwnd){ /* if bic is slower than tcp */ + if (ca->tcp_cwnd > cwnd) { /* if bic is slower than tcp */ delta = ca->tcp_cwnd - cwnd; max_cnt = cwnd / delta; if (ca->cnt > max_cnt) @@ -320,7 +322,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) bictcp_update(ca, tp->snd_cwnd); tcp_cong_avoid_ai(tp, ca->cnt); } - } static u32 bictcp_recalc_ssthresh(struct sock *sk) @@ -452,7 +453,8 @@ static int __init cubictcp_register(void) * based on SRTT of 100ms */ - beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta); + beta_scale = 8*(BICTCP_BETA_SCALE+beta) / 3 + / (BICTCP_BETA_SCALE - beta); cube_rtt_scale = (bic_scale * 10); /* 1024*c/rtt */ diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index a56461c21b97d8c41694de5612dfb38bf8b25829..1d745eac7b8f04f6a70dbcbf6c4e09e55a0dcb23 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ - #include #include #include @@ -37,13 +36,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, } static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct inet_diag_req_v2 *r, struct nlattr *bc) + struct inet_diag_req_v2 *r, struct nlattr *bc) { inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc); } static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - struct inet_diag_req_v2 *req) + struct inet_diag_req_v2 *req) { return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req); } diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index 30f27f6b3655fb030b8f501c700c90ad7fb91b38..aecca537484ffd8886e098e6489b9946762d0f25 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c @@ -9,7 +9,6 @@ #include #include - /* From AIMD tables from RFC 3649 appendix B, * with fixed-point MD scaled <<8. */ @@ -17,78 +16,78 @@ static const struct hstcp_aimd_val { unsigned int cwnd; unsigned int md; } hstcp_aimd_vals[] = { - { 38, 128, /* 0.50 */ }, - { 118, 112, /* 0.44 */ }, - { 221, 104, /* 0.41 */ }, - { 347, 98, /* 0.38 */ }, - { 495, 93, /* 0.37 */ }, - { 663, 89, /* 0.35 */ }, - { 851, 86, /* 0.34 */ }, - { 1058, 83, /* 0.33 */ }, - { 1284, 81, /* 0.32 */ }, - { 1529, 78, /* 0.31 */ }, - { 1793, 76, /* 0.30 */ }, - { 2076, 74, /* 0.29 */ }, - { 2378, 72, /* 0.28 */ }, - { 2699, 71, /* 0.28 */ }, - { 3039, 69, /* 0.27 */ }, - { 3399, 68, /* 0.27 */ }, - { 3778, 66, /* 0.26 */ }, - { 4177, 65, /* 0.26 */ }, - { 4596, 64, /* 0.25 */ }, - { 5036, 62, /* 0.25 */ }, - { 5497, 61, /* 0.24 */ }, - { 5979, 60, /* 0.24 */ }, - { 6483, 59, /* 0.23 */ }, - { 7009, 58, /* 0.23 */ }, - { 7558, 57, /* 0.22 */ }, - { 8130, 56, /* 0.22 */ }, - { 8726, 55, /* 0.22 */ }, - { 9346, 54, /* 0.21 */ }, - { 9991, 53, /* 0.21 */ }, - { 10661, 52, /* 0.21 */ }, - { 11358, 52, /* 0.20 */ }, - { 12082, 51, /* 0.20 */ }, - { 12834, 50, /* 0.20 */ }, - { 13614, 49, /* 0.19 */ }, - { 14424, 48, /* 0.19 */ }, - { 15265, 48, /* 0.19 */ }, - { 16137, 47, /* 0.19 */ }, - { 17042, 46, /* 0.18 */ }, - { 17981, 45, /* 0.18 */ }, - { 18955, 45, /* 0.18 */ }, - { 19965, 44, /* 0.17 */ }, - { 21013, 43, /* 0.17 */ }, - { 22101, 43, /* 0.17 */ }, - { 23230, 42, /* 0.17 */ }, - { 24402, 41, /* 0.16 */ }, - { 25618, 41, /* 0.16 */ }, - { 26881, 40, /* 0.16 */ }, - { 28193, 39, /* 0.16 */ }, - { 29557, 39, /* 0.15 */ }, - { 30975, 38, /* 0.15 */ }, - { 32450, 38, /* 0.15 */ }, - { 33986, 37, /* 0.15 */ }, - { 35586, 36, /* 0.14 */ }, - { 37253, 36, /* 0.14 */ }, - { 38992, 35, /* 0.14 */ }, - { 40808, 35, /* 0.14 */ }, - { 42707, 34, /* 0.13 */ }, - { 44694, 33, /* 0.13 */ }, - { 46776, 33, /* 0.13 */ }, - { 48961, 32, /* 0.13 */ }, - { 51258, 32, /* 0.13 */ }, - { 53677, 31, /* 0.12 */ }, - { 56230, 30, /* 0.12 */ }, - { 58932, 30, /* 0.12 */ }, - { 61799, 29, /* 0.12 */ }, - { 64851, 28, /* 0.11 */ }, - { 68113, 28, /* 0.11 */ }, - { 71617, 27, /* 0.11 */ }, - { 75401, 26, /* 0.10 */ }, - { 79517, 26, /* 0.10 */ }, - { 84035, 25, /* 0.10 */ }, - { 89053, 24, /* 0.10 */ }, + { 38, 128, /* 0.50 */ }, + { 118, 112, /* 0.44 */ }, + { 221, 104, /* 0.41 */ }, + { 347, 98, /* 0.38 */ }, + { 495, 93, /* 0.37 */ }, + { 663, 89, /* 0.35 */ }, + { 851, 86, /* 0.34 */ }, + { 1058, 83, /* 0.33 */ }, + { 1284, 81, /* 0.32 */ }, + { 1529, 78, /* 0.31 */ }, + { 1793, 76, /* 0.30 */ }, + { 2076, 74, /* 0.29 */ }, + { 2378, 72, /* 0.28 */ }, + { 2699, 71, /* 0.28 */ }, + { 3039, 69, /* 0.27 */ }, + { 3399, 68, /* 0.27 */ }, + { 3778, 66, /* 0.26 */ }, + { 4177, 65, /* 0.26 */ }, + { 4596, 64, /* 0.25 */ }, + { 5036, 62, /* 0.25 */ }, + { 5497, 61, /* 0.24 */ }, + { 5979, 60, /* 0.24 */ }, + { 6483, 59, /* 0.23 */ }, + { 7009, 58, /* 0.23 */ }, + { 7558, 57, /* 0.22 */ }, + { 8130, 56, /* 0.22 */ }, + { 8726, 55, /* 0.22 */ }, + { 9346, 54, /* 0.21 */ }, + { 9991, 53, /* 0.21 */ }, + { 10661, 52, /* 0.21 */ }, + { 11358, 52, /* 0.20 */ }, + { 12082, 51, /* 0.20 */ }, + { 12834, 50, /* 0.20 */ }, + { 13614, 49, /* 0.19 */ }, + { 14424, 48, /* 0.19 */ }, + { 15265, 48, /* 0.19 */ }, + { 16137, 47, /* 0.19 */ }, + { 17042, 46, /* 0.18 */ }, + { 17981, 45, /* 0.18 */ }, + { 18955, 45, /* 0.18 */ }, + { 19965, 44, /* 0.17 */ }, + { 21013, 43, /* 0.17 */ }, + { 22101, 43, /* 0.17 */ }, + { 23230, 42, /* 0.17 */ }, + { 24402, 41, /* 0.16 */ }, + { 25618, 41, /* 0.16 */ }, + { 26881, 40, /* 0.16 */ }, + { 28193, 39, /* 0.16 */ }, + { 29557, 39, /* 0.15 */ }, + { 30975, 38, /* 0.15 */ }, + { 32450, 38, /* 0.15 */ }, + { 33986, 37, /* 0.15 */ }, + { 35586, 36, /* 0.14 */ }, + { 37253, 36, /* 0.14 */ }, + { 38992, 35, /* 0.14 */ }, + { 40808, 35, /* 0.14 */ }, + { 42707, 34, /* 0.13 */ }, + { 44694, 33, /* 0.13 */ }, + { 46776, 33, /* 0.13 */ }, + { 48961, 32, /* 0.13 */ }, + { 51258, 32, /* 0.13 */ }, + { 53677, 31, /* 0.12 */ }, + { 56230, 30, /* 0.12 */ }, + { 58932, 30, /* 0.12 */ }, + { 61799, 29, /* 0.12 */ }, + { 64851, 28, /* 0.11 */ }, + { 68113, 28, /* 0.11 */ }, + { 71617, 27, /* 0.11 */ }, + { 75401, 26, /* 0.10 */ }, + { 79517, 26, /* 0.10 */ }, + { 84035, 25, /* 0.10 */ }, + { 89053, 24, /* 0.10 */ }, }; #define HSTCP_AIMD_MAX ARRAY_SIZE(hstcp_aimd_vals) diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index c1a8175361e896a37c515b93ed64f23f0cd311ee..d40615e7e460c4c26a6947d8deccfdc0df0c72e4 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -98,7 +98,8 @@ static inline void measure_rtt(struct sock *sk, u32 srtt) } } -static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, s32 rtt) +static void measure_achieved_throughput(struct sock *sk, + u32 pkts_acked, s32 rtt) { const struct inet_connection_sock *icsk = inet_csk(sk); const struct tcp_sock *tp = tcp_sk(sk); @@ -148,8 +149,8 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT) if (use_bandwidth_switch) { u32 maxB = ca->maxB; u32 old_maxB = ca->old_maxB; - ca->old_maxB = ca->maxB; + ca->old_maxB = ca->maxB; if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { ca->beta = BETA_MIN; ca->modeswitch = 0; @@ -270,6 +271,7 @@ static void htcp_state(struct sock *sk, u8 new_state) case TCP_CA_Open: { struct htcp *ca = inet_csk_ca(sk); + if (ca->undo_last_cong) { ca->last_cong = jiffies; ca->undo_last_cong = 0; diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c index 57bdd17dff4d0abfcce0b4ee1078b8e442101371..b5100aaea1a0d8e28f6d688ffc92ec5f316239f2 100644 --- a/net/ipv4/tcp_hybla.c +++ b/net/ipv4/tcp_hybla.c @@ -29,7 +29,6 @@ static int rtt0 = 25; module_param(rtt0, int, 0644); MODULE_PARM_DESC(rtt0, "reference rout trip time (ms)"); - /* This is called to refresh values for hybla parameters */ static inline void hybla_recalc_param (struct sock *sk) { diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 86183c4e4fd54a231933e09bd3d0b62c8228699e..6845012e6fbb2974788a3552235d9110f5460caf 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -284,7 +284,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) delta = (tp->snd_cwnd_cnt * ca->alpha) >> ALPHA_SHIFT; if (delta >= tp->snd_cwnd) { tp->snd_cwnd = min(tp->snd_cwnd + delta / tp->snd_cwnd, - (u32) tp->snd_cwnd_clamp); + (u32)tp->snd_cwnd_clamp); tp->snd_cwnd_cnt = 0; } } @@ -299,7 +299,6 @@ static u32 tcp_illinois_ssthresh(struct sock *sk) return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->beta) >> BETA_SHIFT), 2U); } - /* Extract info for Tcp socket info provided via netlink. */ static void tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 7ea3c2a80b40f5557d97206c6a0f280113743bec..8b039a79c8d43095e38d07d74f970fdbcaf9975d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -89,7 +89,6 @@ int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; EXPORT_SYMBOL(sysctl_tcp_low_latency); - #ifdef CONFIG_TCP_MD5SIG static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, __be32 daddr, __be32 saddr, const struct tcphdr *th); @@ -629,7 +628,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (skb_rtable(skb)->rt_type != RTN_LOCAL) + /* If sk not NULL, it means we did a successful lookup and incoming + * route had to be correct. prequeue might have dropped our dst. + */ + if (!sk && skb_rtable(skb)->rt_type != RTN_LOCAL) return; /* Swap the send and the receive. */ @@ -651,6 +653,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); + net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); #ifdef CONFIG_TCP_MD5SIG hash_location = tcp_parse_md5sig_option(th); if (!sk && hash_location) { @@ -661,7 +664,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) * Incoming packet is checked with md5 hash with finding key, * no RST generated if md5 hash doesn't match. */ - sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + sk1 = __inet_lookup_listener(net, &tcp_hashinfo, ip_hdr(skb)->saddr, th->source, ip_hdr(skb)->daddr, ntohs(th->source), inet_iif(skb)); @@ -709,8 +712,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (sk) arg.bound_dev_if = sk->sk_bound_dev_if; - net = dev_net(skb_dst(skb)->dev); arg.tos = ip_hdr(skb)->tos; + arg.uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL); ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len); @@ -731,7 +734,8 @@ release_sk1: outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, +static void tcp_v4_send_ack(const struct sock *sk, struct sk_buff *skb, + u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, struct tcp_md5sig_key *key, int reply_flags, u8 tos) @@ -746,7 +750,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, ]; } rep; struct ip_reply_arg arg; - struct net *net = dev_net(skb_dst(skb)->dev); + struct net *net = sock_net(sk); memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof(arg)); @@ -795,6 +799,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, if (oif) arg.bound_dev_if = oif; arg.tos = tos; + arg.uid = sock_net_uid(net, sk_fullsock(sk) ? sk : NULL); ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len); @@ -807,7 +812,7 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcp_time_stamp + tcptw->tw_ts_offset, tcptw->tw_ts_recent, @@ -826,14 +831,14 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV * sk->sk_state == TCP_SYN_RECV -> for Fast Open. */ - tcp_v4_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? + tcp_v4_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, tcp_rsk(req)->rcv_nxt, req->rcv_wnd >> inet_rsk(req)->rcv_wscale, tcp_time_stamp, req->ts_recent, 0, - tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, AF_INET), inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, ip_hdr(skb)->tos); @@ -1284,7 +1289,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_ack = tcp_v4_reqsk_send_ack, .destructor = tcp_v4_reqsk_destructor, .send_reset = tcp_v4_send_reset, - .syn_ack_timeout = tcp_syn_ack_timeout, + .syn_ack_timeout = tcp_syn_ack_timeout, }; #ifdef CONFIG_TCP_MD5SIG @@ -1801,7 +1806,7 @@ static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) /* The socket must have it's spinlock held when we get - * here, unless it is a TCP_LISTEN socket. + * here. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. @@ -1938,7 +1943,17 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) skb_queue_len(&tp->ucopy.prequeue) == 0) return false; - skb_dst_force(skb); + /* Before escaping RCU protected region, we need to take care of skb + * dst. Prequeue is only enabled for established sockets. + * For such sockets, we might need the skb dst only to set sk->sk_rx_dst + * Instead of doing full sk_rx_dst validity here, let's perform + * an optimistic check. + */ + if (likely(sk->sk_rx_dst)) + skb_dst_drop(skb); + else + skb_dst_force_safe(skb); + __skb_queue_tail(&tp->ucopy.prequeue, skb); tp->ucopy.memory += skb->truesize; if (tp->ucopy.memory > sk->sk_rcvbuf) { @@ -2049,11 +2064,6 @@ process: skb->dev = NULL; - if (sk->sk_state == TCP_LISTEN) { - ret = tcp_v4_do_rcv(sk, skb); - goto put_and_return; - } - bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { @@ -2077,7 +2087,6 @@ process: } bh_unlock_sock(sk); -put_and_return: sock_put(sk); return ret; @@ -2153,9 +2162,10 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - dst_hold(dst); - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + if (dst && dst_hold_safe(dst)) { + sk->sk_rx_dst = dst; + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + } } EXPORT_SYMBOL(inet_sk_rx_dst_set); @@ -2629,7 +2639,7 @@ int tcp_seq_open(struct inode *inode, struct file *file) s = ((struct seq_file *)file->private_data)->private; s->family = afinfo->family; - s->last_pos = 0; + s->last_pos = 0; return 0; } EXPORT_SYMBOL(tcp_seq_open); diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c index 8ce55b8aaec8476e3b8292ddd7bf10c98ac402b2..e018e734a4de9a1c1bdf3a93e2379c1f742c7bc3 100644 --- a/net/ipv4/tcp_scalable.c +++ b/net/ipv4/tcp_scalable.c @@ -31,10 +31,10 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) static u32 tcp_scalable_ssthresh(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); + return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U); } - static struct tcp_congestion_ops tcp_scalable __read_mostly = { .ssthresh = tcp_scalable_ssthresh, .cong_avoid = tcp_scalable_cong_avoid, diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 8c61887277c887c76075eefe0d1495613b193e7f..bb74e4aa112ae0d0f934f3d11b91f5ecc9f4ae8e 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -82,11 +82,19 @@ static void tcp_write_err(struct sock *sk) * to prevent DoS attacks. It is called when a retransmission timeout * or zero probe timeout occurs on orphaned socket. * + * Also close if our net namespace is exiting; in that case there is no + * hope of ever communicating again since all netns interfaces are already + * down (or about to be down), and we need to release our dst references, + * which have been moved to the netns loopback interface, so the namespace + * can finish exiting. This condition is only possible if we are a kernel + * socket, as those do not hold references to the namespace. + * * Criteria is still not confirmed experimentally and may change. * We kill the socket, if: * 1. If number of orphaned sockets exceeds an administratively configured * limit. * 2. If we have strong memory pressure. + * 3. If our net namespace is exiting. */ static int tcp_out_of_resources(struct sock *sk, int do_reset) { @@ -115,6 +123,13 @@ static int tcp_out_of_resources(struct sock *sk, int do_reset) NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); return 1; } + + if (!check_net(sock_net(sk))) { + /* Not possible to send reset; just close */ + tcp_done(sk); + return 1; + } + return 0; } diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index b4d1858be55031183a7555591f43ed4dbcb4bfbe..84363b1924666487b4593aa519c15194fe5cde52 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -175,7 +175,6 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) } else tp->snd_cwnd_cnt++; } - } if (tp->snd_cwnd < 2) tp->snd_cwnd = 2; diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c index 76a1e23259e1fa713bb447486e4e94848e419d41..3c9c80c04e10871b5470aab492d0248099f0ef9d 100644 --- a/net/ipv4/tcp_westwood.c +++ b/net/ipv4/tcp_westwood.c @@ -42,7 +42,6 @@ struct westwood { u8 reset_rtt_min; /* Reset RTT min to next RTT sample*/ }; - /* TCP Westwood functions and constants */ #define TCP_WESTWOOD_RTT_MIN (HZ/20) /* 50ms */ #define TCP_WESTWOOD_INIT_RTT (20*HZ) /* maybe too conservative?! */ @@ -153,7 +152,6 @@ static inline void update_rtt_min(struct westwood *w) w->rtt_min = min(w->rtt, w->rtt_min); } - /* * @westwood_fast_bw * It is called when we are in fast path. In particular it is called when @@ -208,7 +206,6 @@ static inline u32 westwood_acked_count(struct sock *sk) return w->cumul_ack; } - /* * TCP Westwood * Here limit is evaluated as Bw estimation*RTTmin (for obtaining it @@ -219,6 +216,7 @@ static u32 tcp_westwood_bw_rttmin(const struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); const struct westwood *w = inet_csk_ca(sk); + return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2); } @@ -254,12 +252,12 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) } } - /* Extract info for Tcp socket info provided via netlink. */ static void tcp_westwood_info(struct sock *sk, u32 ext, struct sk_buff *skb) { const struct westwood *ca = inet_csk_ca(sk); + if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { struct tcpvegas_info info = { .tcpv_enabled = 1, @@ -271,7 +269,6 @@ static void tcp_westwood_info(struct sock *sk, u32 ext, } } - static struct tcp_congestion_ops tcp_westwood __read_mostly = { .init = tcp_westwood_init, .ssthresh = tcp_reno_ssthresh, diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index bf8321d6f2ef2db596f846d4627d7bfc7b80ee15..80e9c70c0079d3716b815c8f9cee21044e3ba60d 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c @@ -54,10 +54,8 @@ static void tcp_yeah_init(struct sock *sk) /* Ensure the MD arithmetic works. This is somewhat pedantic, * since I don't think we will see a cwnd this large. :) */ tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128); - } - static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, s32 rtt_us) { const struct inet_connection_sock *icsk = inet_csk(sk); @@ -84,7 +82,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) /* Scalable */ tp->snd_cwnd_cnt += yeah->pkts_acked; - if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){ + if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)) { if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; tp->snd_cwnd_cnt = 0; @@ -120,7 +118,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) */ if (after(ack, yeah->vegas.beg_snd_nxt)) { - /* We do the Vegas calculations only if we got enough RTT * samples that we can be reasonably sure that we got * at least one RTT sample that wasn't from a delayed ACK. @@ -189,7 +186,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) } yeah->lastQ = queue; - } /* Save the extent of the current window so we can use this @@ -205,7 +201,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) } } -static u32 tcp_yeah_ssthresh(struct sock *sk) { +static u32 tcp_yeah_ssthresh(struct sock *sk) +{ const struct tcp_sock *tp = tcp_sk(sk); struct yeah *yeah = inet_csk_ca(sk); u32 reduction; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a7fbe7e6f763ff99da78dc0a40350329ec5f1143..fc7667512880b002202e35f516a192b50b823f37 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -971,7 +971,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, - faddr, saddr, dport, inet->inet_sport); + faddr, saddr, dport, inet->inet_sport, + sk->sk_uid); security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6e92b4f15d25a7916d82d28f97af3779016e484d..3d90a43e641e1c150316a8a4b544d3a8f889db69 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -699,6 +699,7 @@ int inet6_sk_rebuild_header(struct sock *sk) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sk->sk_uid; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); rcu_read_lock(); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index bb02e176cb70537ac7cdc01a03c0c641ab672741..15e41c5bea3a9872b6ed6d71d2afdca7ba9e1e6f 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -628,9 +628,9 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); xfrm_state_put(x); } diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 0deea6ef4cc1eda275346ca9252460246cd9f183..8abb98c38d3e69ab03ef580c600e29103a1fa41f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -162,6 +162,7 @@ ipv4_connected: fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sk->sk_uid; if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST)) fl6.flowi6_oif = np->mcast_oif; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 40ffd72243a4f2d1ec9e5da494b3f2650dd027a6..4ad65258f549aefc50e78eccfff914b81f7eecab 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -447,9 +447,9 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); xfrm_state_put(x); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 84bdcd06dd34bcb89bc2d13a1750c7d0f19dec40..adb715b22f73ffe2f6d41ea4ed33cb5654393b8c 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -90,9 +90,9 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct net *net = dev_net(skb->dev); if (type == ICMPV6_PKT_TOOBIG) - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); else if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); if (!(type & ICMPV6_INFOMSG_MASK)) if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST) @@ -467,6 +467,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) fl6.flowi6_oif = iif; fl6.fl6_icmp_type = type; fl6.fl6_icmp_code = code; + fl6.flowi6_uid = sock_net_uid(net, NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); sk = icmpv6_xmit_lock(net); @@ -572,6 +573,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl6.flowi6_oif = skb->dev->ifindex; fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; fl6.flowi6_mark = mark; + fl6.flowi6_uid = sock_net_uid(net, NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); sk = icmpv6_xmit_lock(net); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 9cdb8e434513a43de2854f35c234bbbf9374777e..a2072a81c933b7c1ed6f34924c49862e0178e68b 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -86,6 +86,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, fl6->flowi6_mark = inet_rsk(req)->ir_mark; fl6->fl6_dport = inet_rsk(req)->rmt_port; fl6->fl6_sport = inet_rsk(req)->loc_port; + fl6->flowi6_uid = sk->sk_uid; security_req_classify_flow(req, flowi6_to_flowi(fl6)); dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); @@ -213,6 +214,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, fl6->flowi6_mark = sk->sk_mark; fl6->fl6_sport = inet->inet_sport; fl6->fl6_dport = inet->inet_dport; + fl6->flowi6_uid = sk->sk_uid; security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); rcu_read_lock(); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 529348e6a98be10576cff0835ab07db2a1fde703..70453acb83852a1fa0c275df693df06781a1711b 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -801,6 +801,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) fl6.flowi6_mark = skb->mark; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); if (err != 0) { /* XXX: send ICMP error even if DF is not set. */ @@ -851,6 +853,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) fl6.flowi6_mark = skb->mark; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); if (err != 0) { if (err == -EMSGSIZE) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c681f4f760e6ca1569924fd678fc45a2e0f9a6d6..ae0b68e28943cfd99731b33288d9321dc6b960aa 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1464,7 +1464,8 @@ alloc_new_skb: if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index efc77acbe9e193d4730ec99fc66ea38c4f247607..cd0a8bed1ea47d82b7e75bd252258beafdb7ad44 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1096,6 +1096,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); fl6.flowi6_proto = IPPROTO_IPIP; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + dsfield = ipv4_get_dsfield(iph); if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) @@ -1147,6 +1149,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); fl6.flowi6_proto = IPPROTO_IPV6; + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); dsfield = ipv6_get_dsfield(ipv6h); if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 13d47e177665c6875785009b906a02d47365de8a..d9811e4079aef90e4ae4863ada2cb93b65e0c988 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1662,6 +1662,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns struct net *net = sock_net(sk); struct mr6_table *mrt; + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->inet_num != IPPROTO_ICMPV6) + return -EOPNOTSUPP; + mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); if (mrt == NULL) return -ENOENT; @@ -1673,9 +1677,6 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns switch (optname) { case MRT6_INIT: - if (sk->sk_type != SOCK_RAW || - inet_sk(sk)->inet_num != IPPROTO_ICMPV6) - return -EOPNOTSUPP; if (optlen < sizeof(int)) return -EINVAL; @@ -1811,6 +1812,10 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, struct net *net = sock_net(sk); struct mr6_table *mrt; + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->inet_num != IPPROTO_ICMPV6) + return -EOPNOTSUPP; + mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); if (mrt == NULL) return -ENOENT; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 7af5aee75d982327e7b258f72091780e83a01cc4..a4a4e1c2c9faf96f5ad88387f01a4211fe2484b7 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -76,9 +76,9 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, 0, 0); + ip6_redirect(skb, net, 0, 0, sock_net_uid(net, NULL)); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); xfrm_state_put(x); } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f4d2412d9c608f5e15e20f685c12b565c190858b..e76412f822d35aacea22f8aa59b37dcdc47f3503 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -871,12 +871,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && - optname != IPV6_XFRM_POLICY) { - lock_sock(sk); - err = nf_setsockopt(sk, PF_INET6, optname, optval, - optlen); - release_sock(sk); - } + optname != IPV6_XFRM_POLICY) + err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen); #endif return err; } @@ -907,12 +903,9 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && - optname != IPV6_XFRM_POLICY) { - lock_sock(sk); - err = compat_nf_setsockopt(sk, PF_INET6, optname, - optval, optlen); - release_sock(sk); - } + optname != IPV6_XFRM_POLICY) + err = compat_nf_setsockopt(sk, PF_INET6, optname, optval, + optlen); #endif return err; } diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index d38e6a8d8b9fb82ec7d583a5ab2abc652838d470..e48d26beda464fb627c560d34c5aa81fd2cdb7c1 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -27,6 +27,7 @@ int ip6_route_me_harder(struct sk_buff *skb) struct flowi6 fl6 = { .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, .flowi6_mark = skb->mark, + .flowi6_uid = sock_net_uid(net, skb->sk), .daddr = iph->daddr, .saddr = iph->saddr, }; diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 7f45af3e812807d7b8bb2c77f82e47d579a65559..9488916d1f2be5b7e2a61aaa8ea78a824ce39873 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -105,7 +105,8 @@ config IP6_NF_MATCH_MH config IP6_NF_MATCH_RPFILTER tristate '"rpfilter" reverse path filter match support' - depends on NETFILTER_ADVANCED && (IP6_NF_MANGLE || IP6_NF_RAW) + depends on NETFILTER_ADVANCED + depends on IP6_NF_MANGLE || IP6_NF_RAW ---help--- This option allows you to match packets whose replies would go out via the interface the packet came in. diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 9802b24696625defdeee3c1b7552aa2f875ae35e..8a8d1571cf2f687962d25efe5e643504344dc958 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1592,6 +1592,8 @@ translate_compat_table(struct net *net, if (!newinfo) goto out_unlock; + memset(newinfo->entries, 0, size); + newinfo->number = compatr->num_entries; for (i = 0; i < NF_INET_NUMHOOKS; i++) { newinfo->hook_entry[i] = compatr->hook_entry[i]; diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 97cd7507c1a40251cefac656f942c87ae901d318..695d0095a3853ad8923e45f30cab2041b4d17357 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -243,20 +243,27 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { static int ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) { - const struct inet_sock *inet = inet_sk(sk); + struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; const struct ipv6_pinfo *inet6 = inet6_sk(sk); + const struct inet_sock *inet = inet_sk(sk); const struct nf_conntrack_tuple_hash *h; struct sockaddr_in6 sin6; - struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; struct nf_conn *ct; + __be32 flow_label; + int bound_dev_if; + lock_sock(sk); tuple.src.u3.in6 = inet6->rcv_saddr; tuple.src.u.tcp.port = inet->inet_sport; tuple.dst.u3.in6 = inet6->daddr; tuple.dst.u.tcp.port = inet->inet_dport; tuple.dst.protonum = sk->sk_protocol; + bound_dev_if = sk->sk_bound_dev_if; + flow_label = inet6->flow_label; + release_sock(sk); - if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) + if (tuple.dst.protonum != IPPROTO_TCP && + tuple.dst.protonum != IPPROTO_SCTP) return -ENOPROTOOPT; if (*len < 0 || (unsigned int) *len < sizeof(sin6)) @@ -274,14 +281,13 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) sin6.sin6_family = AF_INET6; sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; - sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK; + sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK; memcpy(&sin6.sin6_addr, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, sizeof(sin6.sin6_addr)); nf_ct_put(ct); - sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, - sk->sk_bound_dev_if); + sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if); return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; } diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index d40ef970746b70dbda5582b97699a6a54eac2985..6f71b7e0f075eacdbf1bee9539f196a37b72e5ae 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -3,9 +3,42 @@ * not configured or static. These functions are needed by GSO/GRO implementation. */ #include +#include #include #include +/* This function exists only for tap drivers that must support broken + * clients requesting UFO without specifying an IPv6 fragment ID. + * + * This is similar to ipv6_select_ident() but we use an independent hash + * seed to limit information leakage. + * + * The network header must be set before calling this. + */ +void ipv6_proxy_select_ident(struct sk_buff *skb) +{ + static u32 ip6_proxy_idents_hashrnd __read_mostly; + struct in6_addr buf[2]; + struct in6_addr *addrs; + u32 hash, id; + + addrs = skb_header_pointer(skb, + skb_network_offset(skb) + + offsetof(struct ipv6hdr, saddr), + sizeof(buf), buf); + if (!addrs) + return; + + net_get_random_once(&ip6_proxy_idents_hashrnd, + sizeof(ip6_proxy_idents_hashrnd)); + + hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd); + hash = __ipv6_addr_jhash(&addrs[0], hash); + + id = ip_idents_reserve(hash, 1); + skb_shinfo(skb)->ip6_frag_id = htonl(id); +} +EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 9215ccbec01fdb1177e44679e60fe9819b5ec6cb..3cb40fb0f7cff2a61720e175b4641759652003b7 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -161,6 +161,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, fl6.saddr = np->saddr; fl6.daddr = *daddr; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; fl6.fl6_icmp_type = user_icmph.icmp6_type; fl6.fl6_icmp_code = user_icmph.icmp6_code; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 513dffdc2aef2eedf012a9eea30af4c2263a4861..5e0e0594576401d50fe2fc9f122f2930427ed8a6 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -765,6 +765,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; if (sin6) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 335d3fc76f46cd5a77a4b538b047fdcbfb98e91b..5481f1dd6a5dff168c49aa838aea05ee1bfb2915 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1146,7 +1146,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, } void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, - int oif, u32 mark) + int oif, u32 mark, kuid_t uid) { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; @@ -1159,6 +1159,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, fl6.daddr = iph->daddr; fl6.saddr = iph->saddr; fl6.flowlabel = ip6_flowinfo(iph); + fl6.flowi6_uid = uid; dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) @@ -1170,11 +1171,12 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu); void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) { ip6_update_pmtu(skb, sock_net(sk), mtu, - sk->sk_bound_dev_if, sk->sk_mark); + sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid); } EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu); -void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) +void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, + kuid_t uid) { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; @@ -1187,6 +1189,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) fl6.daddr = iph->daddr; fl6.saddr = iph->saddr; fl6.flowlabel = ip6_flowinfo(iph); + fl6.flowi6_uid = uid; dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) @@ -1197,7 +1200,8 @@ EXPORT_SYMBOL_GPL(ip6_redirect); void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk) { - ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark); + ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark, + sk->sk_uid); } EXPORT_SYMBOL_GPL(ip6_sk_redirect); diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index a596f388339d0a227c874dfb61514b7d098d345d..0428544a2bed414b5824c07ea77792fb65043748 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -243,6 +243,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) fl6.flowi6_mark = ireq->ir_mark; fl6.fl6_dport = inet_rsk(req)->rmt_port; fl6.fl6_sport = inet_sk(sk)->inet_sport; + fl6.flowi6_uid = sk->sk_uid; security_req_classify_flow(req, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5ef9d7a0f02e731b4e4cd99e62ffb2e7d0d89509..f4bcb07b21da2fca4bd3af249029c2f5f4ef7991 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -94,13 +94,15 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - const struct rt6_info *rt = (const struct rt6_info *)dst; - dst_hold(dst); - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; - if (rt->rt6i_node) - inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; + if (dst && dst_hold_safe(dst)) { + const struct rt6_info *rt = (const struct rt6_info *)dst; + + sk->sk_rx_dst = dst; + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + if (rt->rt6i_node) + inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; + } } static void tcp_v6_hash(struct sock *sk) @@ -253,6 +255,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = usin->sin6_port; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sk->sk_uid; opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); final_p = fl6_update_dst(&fl6, opt, &final); @@ -723,15 +726,15 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { }; #endif -static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, - u32 tsval, u32 tsecr, +static void tcp_v6_send_response(struct sock *sk, struct sk_buff *skb, u32 seq, + u32 ack, u32 win, u32 tsval, u32 tsecr, struct tcp_md5sig_key *key, int rst, u8 tclass) { const struct tcphdr *th = tcp_hdr(skb); struct tcphdr *t1; struct sk_buff *buff; struct flowi6 fl6; - struct net *net = dev_net(skb_dst(skb)->dev); + struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); struct dst_entry *dst; @@ -799,6 +802,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark); fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; + fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); /* Pass a socket to ip6_dst_lookup either it is for RST @@ -834,7 +838,10 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (!ipv6_unicast_destination(skb)) + /* If sk not NULL, it means we did a successful lookup and incoming + * route had to be correct. prequeue might have dropped our dst. + */ + if (!sk && !ipv6_unicast_destination(skb)) return; #ifdef CONFIG_TCP_MD5SIG @@ -873,7 +880,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - (th->doff << 2); - tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0); + tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, key, 1, 0); #ifdef CONFIG_TCP_MD5SIG release_sk1: @@ -884,11 +891,12 @@ release_sk1: #endif } -static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, - u32 win, u32 tsval, u32 tsecr, +static void tcp_v6_send_ack(struct sock *sk, struct sk_buff *skb, + u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, struct tcp_md5sig_key *key, u8 tclass) { - tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass); + tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, key, 0, + tclass); } static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) @@ -896,7 +904,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcp_time_stamp + tcptw->tw_ts_offset, tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), @@ -913,10 +921,10 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, * exception of segments, MUST be right-shifted by * Rcv.Wind.Shift bits: */ - tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, + tcp_v6_send_ack(sk, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd >> inet_rsk(req)->rcv_wscale, tcp_time_stamp, req->ts_recent, - tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), 0); } @@ -1313,7 +1321,7 @@ static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) } /* The socket must have it's spinlock held when we get - * here, unless it is a TCP_LISTEN socket. + * here. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. @@ -1520,11 +1528,6 @@ process: skb->dev = NULL; - if (sk->sk_state == TCP_LISTEN) { - ret = tcp_v6_do_rcv(sk, skb); - goto put_and_return; - } - bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { @@ -1548,7 +1551,6 @@ process: } bh_unlock_sock(sk); -put_and_return: sock_put(sk); return ret ? -1 : 0; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5187bf51592b7f55125c9865de984423ade54094..cb3fd4fe75d19fd8387c36030b214fea4c16e344 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1149,6 +1149,7 @@ do_udp_sendmsg: fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; if (msg->msg_controllen) { opt = &opt_space; diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 8783dfe5ac6ca74c6d5ea6df5f96a1b7e37826a8..5bd181e296e53d7f3277f08b9930133cc088fafa 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -517,6 +517,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sk->sk_uid; if (lsa) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 9d140594082c655bcf2e4857deeff2b4de379693..7b33b83f2f2de65048e19400f554b073cd2baf70 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -613,7 +613,7 @@ static int llc_wait_data(struct sock *sk, long timeo) if (signal_pending(current)) break; rc = 0; - if (sk_wait_data(sk, &timeo)) + if (sk_wait_data(sk, &timeo, NULL)) break; } return rc; @@ -803,7 +803,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, release_sock(sk); lock_sock(sk); } else - sk_wait_data(sk, &timeo); + sk_wait_data(sk, &timeo, NULL); if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) { net_dbg_ratelimited("LLC(%s:%d): Application bug, race in MSG_PEEK\n", diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b24cfa39bb9473b6862db96a268f33f647d43efd..643be8b0f00d1f445ca0490ade40b8d2802334ec 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1423,14 +1423,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac) + struct station_del_parameters *params) { struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (mac) - return sta_info_destroy_addr_bss(sdata, mac); + if (params->mac) + return sta_info_destroy_addr_bss(sdata, params->mac); sta_info_flush(sdata); return 0; diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 81fce903aeb268fcc6955a267c133b2ccdbc8e96..59210127c502350b7fd945faa7ace441cbd0468e 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -195,7 +195,7 @@ config NF_CONNTRACK_FTP config NF_CONNTRACK_H323 tristate "H.323 protocol support" - depends on (IPV6 || IPV6=n) + depends on IPV6 || IPV6=n depends on NETFILTER_ADVANCED help H.323 is a VoIP signalling protocol from ITU-T. As one of the most @@ -583,7 +583,7 @@ config NETFILTER_XT_TARGET_HL config NETFILTER_XT_TARGET_HMARK tristate '"HMARK" target support' - depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n depends on NETFILTER_ADVANCED ---help--- This option adds the "HMARK" target. @@ -727,7 +727,7 @@ config NETFILTER_XT_TARGET_REDIRECT config NETFILTER_XT_TARGET_TEE tristate '"TEE" - packet cloning to alternate destination' depends on NETFILTER_ADVANCED - depends on (IPV6 || IPV6=n) + depends on IPV6 || IPV6=n depends on !NF_CONNTRACK || NF_CONNTRACK ---help--- This option adds a "TEE" target with which a packet can be cloned and @@ -738,6 +738,7 @@ config NETFILTER_XT_TARGET_TPROXY depends on NETFILTER_TPROXY depends on NETFILTER_XTABLES depends on NETFILTER_ADVANCED + depends on IPV6 || IPV6=n select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES help @@ -772,7 +773,7 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_TCPMSS tristate '"TCPMSS" target support' - depends on (IPV6 || IPV6=n) + depends on IPV6 || IPV6=n default m if NETFILTER_ADVANCED=n ---help--- This option adds a `TCPMSS' target, which allows you to alter the @@ -974,7 +975,7 @@ config NETFILTER_XT_MATCH_ESP config NETFILTER_XT_MATCH_HASHLIMIT tristate '"hashlimit" match support' - depends on (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n depends on NETFILTER_ADVANCED help This option adds a `hashlimit' match. @@ -1240,6 +1241,7 @@ config NETFILTER_XT_MATCH_SOCKET depends on NETFILTER_XTABLES depends on NETFILTER_ADVANCED depends on !NF_CONNTRACK || NF_CONNTRACK + depends on IPV6 || IPV6=n select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES help diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index e903c3a4cd8aae0349acd65396f885139a8fd686..6063365484a372dc64375d51f386e4e3d7d79108 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -221,6 +221,9 @@ xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision) { struct xt_match *match; + if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN) + return ERR_PTR(-EINVAL); + match = xt_find_match(nfproto, name, revision); if (IS_ERR(match)) { request_module("%st_%s", xt_prefix[nfproto], name); @@ -265,6 +268,9 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision) { struct xt_target *target; + if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN) + return ERR_PTR(-EINVAL); + target = xt_find_target(af, name, revision); if (IS_ERR(target)) { request_module("%st_%s", xt_prefix[af], name); @@ -378,6 +384,36 @@ textify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto) return buf; } +/** + * xt_check_proc_name - check that name is suitable for /proc file creation + * + * @name: file name candidate + * @size: length of buffer + * + * some x_tables modules wish to create a file in /proc. + * This function makes sure that the name is suitable for this + * purpose, it checks that name is NUL terminated and isn't a 'special' + * name, like "..". + * + * returns negative number on error or 0 if name is useable. + */ +int xt_check_proc_name(const char *name, unsigned int size) +{ + if (name[0] == '\0') + return -EINVAL; + + if (strnlen(name, size) == size) + return -ENAMETOOLONG; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0 || + strchr(name, '/')) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(xt_check_proc_name); + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { @@ -548,7 +584,7 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, { const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; - int pad, off = xt_compat_match_offset(match); + int off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; char name[sizeof(m->u.user.name)]; @@ -558,9 +594,6 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, match->compat_from_user(m->data, cm->data); else memcpy(m->data, cm->data, msize - sizeof(*cm)); - pad = XT_ALIGN(match->matchsize) - match->matchsize; - if (pad > 0) - memset(m->data + match->matchsize, 0, pad); msize += off; m->u.user.match_size = msize; @@ -662,6 +695,9 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets); * * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. * + * This function does not validate the targets or matches themselves, it + * only tests that all the offsets and sizes are correct. + * * The arp/ip/ip6t_entry structure @base must have passed following tests: * - it must point to a valid memory location * - base to base + next_offset must be accessible, i.e. not exceed allocated @@ -808,7 +844,7 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len, if (copy_from_user(&compat_tmp, user, sizeof(compat_tmp)) != 0) return ERR_PTR(-EFAULT); - strlcpy(info->name, compat_tmp.name, sizeof(info->name)); + memcpy(info->name, compat_tmp.name, sizeof(info->name) - 1); info->num_counters = compat_tmp.num_counters; user += sizeof(compat_tmp); } else @@ -821,9 +857,9 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len, if (copy_from_user(info, user, sizeof(*info)) != 0) return ERR_PTR(-EFAULT); - info->name[sizeof(info->name) - 1] = '\0'; user += sizeof(*info); } + info->name[sizeof(info->name) - 1] = '\0'; size = sizeof(struct xt_counters); size *= info->num_counters; @@ -856,7 +892,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, { const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; - int pad, off = xt_compat_target_offset(target); + int off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; char name[sizeof(t->u.user.name)]; @@ -866,9 +902,6 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, target->compat_from_user(t->data, ct->data); else memcpy(t->data, ct->data, tsize - sizeof(*ct)); - pad = XT_ALIGN(target->targetsize) - target->targetsize; - if (pad > 0) - memset(t->data + target->targetsize, 0, pad); tsize += off; t->u.user.target_size = tsize; diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 47dc6836830a9cfe1b329fbdddabfd1d80c4d100..597d722fb645ed4aad3b7d1c6f88a28dbd098675 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -668,8 +668,9 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par) if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) return -EINVAL; - if (info->name[sizeof(info->name)-1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; if (par->family == NFPROTO_IPV4) { if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32) return -EINVAL; diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index d8b5de301bc4b1b3e385651765e841ea848151f3..599a43dd10eb3284eab32626ebdb8a01c8aa3801 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1071,18 +1071,6 @@ static struct sock_tag *get_sock_stat_nl(const struct sock *sk) return sock_tag_tree_search(&sock_tag_tree, sk); } -static struct sock_tag *get_sock_stat(const struct sock *sk) -{ - struct sock_tag *sock_tag_entry; - MT_DEBUG("qtaguid: get_sock_stat(sk=%p)\n", sk); - if (!sk) - return NULL; - spin_lock_bh(&sock_tag_list_lock); - sock_tag_entry = get_sock_stat_nl(sk); - spin_unlock_bh(&sock_tag_list_lock); - return sock_tag_entry; -} - static int ipx_proto(const struct sk_buff *skb, struct xt_action_param *par) { @@ -1321,12 +1309,15 @@ static void if_tag_stat_update(const char *ifname, uid_t uid, * Look for a tagged sock. * It will have an acct_uid. */ - sock_tag_entry = get_sock_stat(sk); + spin_lock_bh(&sock_tag_list_lock); + sock_tag_entry = sk ? get_sock_stat_nl(sk) : NULL; if (sock_tag_entry) { tag = sock_tag_entry->tag; acct_tag = get_atag_from_tag(tag); uid_tag = get_utag_from_tag(tag); - } else { + } + spin_unlock_bh(&sock_tag_list_lock); + if (!sock_tag_entry) { acct_tag = make_atag_from_value(0); tag = combine_atag_with_uid(acct_tag, uid); uid_tag = make_tag_from_uid(uid); diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 1e657cf715c478d9a9ec77411bf7536b14278d14..db76207bcc4bfe5e25886129e33f1073975d5cfe 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -358,9 +358,9 @@ static int recent_mt_check(const struct xt_mtchk_param *par, info->hit_count, ip_pkt_list_tot); return -EINVAL; } - if (info->name[0] == '\0' || - strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; mutex_lock(&recent_mutex); t = recent_table_lookup(recent_net, info->name); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6f1abd03d8aa7de6bddb09065aec22f03b3eb433..82f1e5e6087e3b4bb5a81e8d7b34c555fb3a9cd5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1393,10 +1393,6 @@ static struct packet_fanout *fanout_release(struct sock *sk) dev_remove_pack(&f->prot_hook); kfree(f); } - if (atomic_dec_and_test(&f->sk_ref)) - list_del(&f->list); - else - f = NULL; } mutex_unlock(&fanout_mutex); @@ -2700,51 +2696,6 @@ out: return err; } -static int packet_recv_error(struct sock *sk, struct msghdr *msg, int len) -{ - struct sock_exterr_skb *serr; - struct sk_buff *skb, *skb2; - int copied, err; - - err = -EAGAIN; - skb = skb_dequeue(&sk->sk_error_queue); - if (skb == NULL) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - if (err) - goto out_free_skb; - - sock_recv_timestamp(msg, sk, skb); - - serr = SKB_EXT_ERR(skb); - put_cmsg(msg, SOL_PACKET, PACKET_TX_TIMESTAMP, - sizeof(serr->ee), &serr->ee); - - msg->msg_flags |= MSG_ERRQUEUE; - err = copied; - - /* Reset and regenerate socket error */ - spin_lock_bh(&sk->sk_error_queue.lock); - sk->sk_err = 0; - if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { - sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; - spin_unlock_bh(&sk->sk_error_queue.lock); - sk->sk_error_report(sk); - } else - spin_unlock_bh(&sk->sk_error_queue.lock); - -out_free_skb: - kfree_skb(skb); -out: - return err; -} - /* * Pull a packet from our receive queue and hand it to the user. * If necessary we block. @@ -2769,7 +2720,8 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, #endif if (flags & MSG_ERRQUEUE) { - err = packet_recv_error(sk, msg, len); + err = sock_recv_errqueue(sk, msg, len, + SOL_PACKET, PACKET_TX_TIMESTAMP); goto out; } diff --git a/net/socket.c b/net/socket.c index 2181d4ab5c56dfe02854869e1933fada4857dfec..6f4fac486e7f03c2b3c432394bb75410ce9f929a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -526,11 +526,11 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, return used; } -int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) +static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) { int err = simple_setattr(dentry, iattr); - if (!err) { + if (!err && (iattr->ia_valid & ATTR_UID)) { struct socket *sock = SOCKET_I(dentry->d_inode); sock->sk->sk_uid = iattr->ia_uid; @@ -1465,48 +1465,61 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, err = fd1; goto out_release_both; } + fd2 = get_unused_fd_flags(flags); if (unlikely(fd2 < 0)) { err = fd2; - put_unused_fd(fd1); - goto out_release_both; + goto out_put_unused_1; } newfile1 = sock_alloc_file(sock1, flags, NULL); if (unlikely(IS_ERR(newfile1))) { err = PTR_ERR(newfile1); - put_unused_fd(fd1); - put_unused_fd(fd2); - goto out_release_both; + goto out_put_unused_both; } newfile2 = sock_alloc_file(sock2, flags, NULL); if (IS_ERR(newfile2)) { err = PTR_ERR(newfile2); - fput(newfile1); - put_unused_fd(fd1); - put_unused_fd(fd2); - sock_release(sock2); - goto out; + goto out_fput_1; } + err = put_user(fd1, &usockvec[0]); + if (err) + goto out_fput_both; + + err = put_user(fd2, &usockvec[1]); + if (err) + goto out_fput_both; + audit_fd_pair(fd1, fd2); + fd_install(fd1, newfile1); fd_install(fd2, newfile2); /* fd1 and fd2 may be already another descriptors. * Not kernel problem. */ - err = put_user(fd1, &usockvec[0]); - if (!err) - err = put_user(fd2, &usockvec[1]); - if (!err) - return 0; + return 0; - sys_close(fd2); - sys_close(fd1); - return err; +out_fput_both: + fput(newfile2); + fput(newfile1); + put_unused_fd(fd2); + put_unused_fd(fd1); + goto out; +out_fput_1: + fput(newfile1); + put_unused_fd(fd2); + put_unused_fd(fd1); + sock_release(sock2); + goto out; + +out_put_unused_both: + put_unused_fd(fd2); +out_put_unused_1: + put_unused_fd(fd1); out_release_both: sock_release(sock2); out_release_1: @@ -2019,6 +2032,9 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) return -EFAULT; + if (kmsg->msg_name == NULL) + kmsg->msg_namelen = 0; + if (kmsg->msg_namelen < 0) return -EINVAL; @@ -2216,6 +2232,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, if (err) break; ++datagrams; + cond_resched(); } fput_light(sock->file, fput_needed); @@ -2435,6 +2452,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, /* Out of band data, return right away */ if (msg_sys.msg_flags & MSG_OOB) break; + cond_resched(); } if (err == 0) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bc0c98754f046eb11020248611b9dedefc5a356e..5b8a81b5ebd78cfd01fd1efb456a44af2086cbc2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4274,10 +4274,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; - u8 *mac_addr = NULL; + struct station_del_parameters params; + + memset(¶ms, 0, sizeof(params)); if (info->attrs[NL80211_ATTR_MAC]) - mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]); if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && @@ -4288,7 +4290,28 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->del_station) return -EOPNOTSUPP; - return rdev_del_station(rdev, dev, mac_addr); + if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) { + params.subtype = + nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); + if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 && + params.subtype != IEEE80211_STYPE_DEAUTH >> 4) + return -EINVAL; + } else { + /* Default to Deauthentication frame */ + params.subtype = IEEE80211_STYPE_DEAUTH >> 4; + } + + if (info->attrs[NL80211_ATTR_REASON_CODE]) { + params.reason_code = + nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (params.reason_code == 0) + return -EINVAL; /* 0 is reserved */ + } else { + /* Default to reason code 2 */ + params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID; + } + + return rdev_del_station(rdev, dev, ¶ms); } static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 6ca59009051305d8eb66aedc6ec3b01c6bea2bdc..9f5ac1eddf4016c2083cbcb64ad280327130f73d 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -177,11 +177,12 @@ static inline int rdev_add_station(struct cfg80211_registered_device *rdev, } static inline int rdev_del_station(struct cfg80211_registered_device *rdev, - struct net_device *dev, u8 *mac) + struct net_device *dev, + struct station_del_parameters *params) { int ret; - trace_rdev_del_station(&rdev->wiphy, dev, mac); - ret = rdev->ops->del_station(&rdev->wiphy, dev, mac); + trace_rdev_del_station(&rdev->wiphy, dev, params); + ret = rdev->ops->del_station(&rdev->wiphy, dev, params); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 6a56998af66c26be59ff3d2ebbe4d946821d0700..a378484fd413415b6f887f8ad2d76b863347293a 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -690,9 +690,34 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) ); -DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), - TP_ARGS(wiphy, netdev, mac) +DECLARE_EVENT_CLASS(station_del, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct station_del_parameters *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(sta_mac) + __field(u8, subtype) + __field(u16, reason_code) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(sta_mac, params->mac); + __entry->subtype = params->subtype; + __entry->reason_code = params->reason_code; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT + ", subtype: %u, reason_code: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), + __entry->subtype, __entry->reason_code) +); + +DEFINE_EVENT(station_del, rdev_del_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct station_del_parameters *params), + TP_ARGS(wiphy, netdev, params) ); DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c9318567d5a36acd8ba032c9ea88565bf1d34b6c..4bf8f2c06d2cec55b6190af11a072723e4f857e5 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -400,9 +400,6 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) return -EINVAL; - if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) - return -EINVAL; - return 0; } @@ -862,11 +859,6 @@ static int copy_to_user_state_extra(struct xfrm_state *x, } if (x->security) ret = copy_sec_ctx(x->security, skb); - if (x->props.output_mark) { - ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark); - if (ret) - goto out; - } out: return ret; } diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 2d30f41778b7270b074798b4439952dca28d9c53..d0eb405cb81148bbd15ca43522f8e5b366dbe8ca 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -637,7 +637,7 @@ char *yytext; #include "srcpos.h" #include "dtc-parser.tab.h" -YYLTYPE yylloc; +extern YYLTYPE yylloc; /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ #define YY_USER_ACTION \ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 09632f04576bed64e185589bad042f740d73d14f..8242233d61d8eeff6bbe9758c1593220103032b5 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -42,49 +42,11 @@ typedef unsigned char __u8; /* This array collects all instances that use the generic do_table */ struct devtable { - const char *device_id; /* name of table, __mod__device_table. */ + const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; void *function; }; -#define ___cat(a,b) a ## b -#define __cat(a,b) ___cat(a,b) - -/* we need some special handling for this host tool running eventually on - * Darwin. The Mach-O section handling is a bit different than ELF section - * handling. The differnces in detail are: - * a) we have segments which have sections - * b) we need a API call to get the respective section symbols */ -#if defined(__MACH__) -#include - -#define INIT_SECTION(name) do { \ - unsigned long name ## _len; \ - char *__cat(pstart_,name) = getsectdata("__TEXT", \ - #name, &__cat(name,_len)); \ - char *__cat(pstop_,name) = __cat(pstart_,name) + \ - __cat(name, _len); \ - __cat(__start_,name) = (void *)__cat(pstart_,name); \ - __cat(__stop_,name) = (void *)__cat(pstop_,name); \ - } while (0) -#define SECTION(name) __attribute__((section("__TEXT, " #name))) - -struct devtable **__start___devtable, **__stop___devtable; -#else -#define INIT_SECTION(name) /* no-op for ELF */ -#define SECTION(name) __attribute__((section(#name))) - -/* We construct a table of pointers in an ELF section (pointers generally - * go unpadded by gcc). ld creates boundary syms for us. */ -extern struct devtable *__start___devtable[], *__stop___devtable[]; -#endif /* __MACH__ */ - -#if __GNUC__ == 3 && __GNUC_MINOR__ < 3 -# define __used __attribute__((__unused__)) -#else -# define __used __attribute__((__used__)) -#endif - /* Define a variable f that holds the value of field f of struct devid * based at address m. */ @@ -97,16 +59,6 @@ extern struct devtable *__start___devtable[], *__stop___devtable[]; #define DEF_FIELD_ADDR(m, devid, f) \ typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) -/* Add a table entry. We test function type matches while we're here. */ -#define ADD_TO_DEVTABLE(device_id, type, function) \ - static struct devtable __cat(devtable,__LINE__) = { \ - device_id + 0*sizeof((function)((const char *)NULL, \ - (void *)NULL, \ - (char *)NULL)), \ - SIZE_##type, (function) }; \ - static struct devtable *SECTION(__devtable) __used \ - __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) - #define ADD(str, sep, cond, field) \ do { \ strcat(str, sep); \ @@ -144,7 +96,8 @@ static void device_id_check(const char *modname, const char *device_id, if (size % id_size || size < id_size) { fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " - "of the size of section __mod_%s_device_table=%lu.\n" + "of the size of " + "section __mod_%s___device_table=%lu.\n" "Fix definition of struct %s_device_id " "in mod_devicetable.h\n", modname, device_id, id_size, device_id, size, device_id); @@ -371,7 +324,6 @@ static int do_hid_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry); /* Looks like: ieee1394:venNmoNspNverN */ static int do_ieee1394_entry(const char *filename, @@ -396,7 +348,6 @@ static int do_ieee1394_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry); /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ static int do_pci_entry(const char *filename, @@ -440,7 +391,6 @@ static int do_pci_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry); /* looks like: "ccw:tNmNdtNdmN" */ static int do_ccw_entry(const char *filename, @@ -464,7 +414,6 @@ static int do_ccw_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry); /* looks like: "ap:tN" */ static int do_ap_entry(const char *filename, @@ -475,7 +424,6 @@ static int do_ap_entry(const char *filename, sprintf(alias, "ap:t%02X*", dev_type); return 1; } -ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry); /* looks like: "css:tN" */ static int do_css_entry(const char *filename, @@ -486,7 +434,6 @@ static int do_css_entry(const char *filename, sprintf(alias, "css:t%01X", type); return 1; } -ADD_TO_DEVTABLE("css", css_device_id, do_css_entry); /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, @@ -506,7 +453,6 @@ static int do_serio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ static int do_acpi_entry(const char *filename, @@ -516,7 +462,6 @@ static int do_acpi_entry(const char *filename, sprintf(alias, "acpi*:%s:*", *id); return 1; } -ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); /* looks like: "pnp:dD" */ static void do_pnp_device_entry(void *symval, unsigned long size, @@ -637,7 +582,6 @@ static int do_pcmcia_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); static int do_of_entry (const char *filename, void *symval, char *alias) { @@ -664,7 +608,6 @@ static int do_of_entry (const char *filename, void *symval, char *alias) add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("of", of_device_id, do_of_entry); static int do_vio_entry(const char *filename, void *symval, char *alias) @@ -684,7 +627,6 @@ static int do_vio_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -757,7 +699,6 @@ static int do_input_entry(const char *filename, void *symval, do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); return 1; } -ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); static int do_eisa_entry(const char *filename, void *symval, char *alias) @@ -769,7 +710,6 @@ static int do_eisa_entry(const char *filename, void *symval, strcat(alias, "*"); return 1; } -ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry); /* Looks like: parisc:tNhvNrevNsvN */ static int do_parisc_entry(const char *filename, void *symval, @@ -789,7 +729,6 @@ static int do_parisc_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry); /* Looks like: sdio:cNvNdN. */ static int do_sdio_entry(const char *filename, @@ -806,7 +745,6 @@ static int do_sdio_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry); /* Looks like: ssb:vNidNrevN. */ static int do_ssb_entry(const char *filename, @@ -823,7 +761,6 @@ static int do_ssb_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); /* Looks like: bcma:mNidNrevNclN. */ static int do_bcma_entry(const char *filename, @@ -842,7 +779,6 @@ static int do_bcma_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry); /* Looks like: virtio:dNvN */ static int do_virtio_entry(const char *filename, void *symval, @@ -858,7 +794,6 @@ static int do_virtio_entry(const char *filename, void *symval, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); /* * Looks like: vmbus:guid @@ -881,7 +816,6 @@ static int do_vmbus_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); /* Looks like: i2c:S */ static int do_i2c_entry(const char *filename, void *symval, @@ -892,7 +826,6 @@ static int do_i2c_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry); /* Looks like: spi:S */ static int do_spi_entry(const char *filename, void *symval, @@ -903,7 +836,6 @@ static int do_spi_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry); static const struct dmifield { const char *prefix; @@ -958,7 +890,6 @@ static int do_dmi_entry(const char *filename, void *symval, strcat(alias, ":"); return 1; } -ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry); static int do_platform_entry(const char *filename, void *symval, char *alias) @@ -967,7 +898,6 @@ static int do_platform_entry(const char *filename, sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry); static int do_mdio_entry(const char *filename, void *symval, char *alias) @@ -992,7 +922,6 @@ static int do_mdio_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry); /* Looks like: zorro:iN. */ static int do_zorro_entry(const char *filename, void *symval, @@ -1003,7 +932,6 @@ static int do_zorro_entry(const char *filename, void *symval, ADD(alias, "i", id != ZORRO_WILDCARD, id); return 1; } -ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry); /* looks like: "pnp:dD" */ static int do_isapnp_entry(const char *filename, @@ -1019,7 +947,6 @@ static int do_isapnp_entry(const char *filename, (function >> 12) & 0x0f, (function >> 8) & 0x0f); return 1; } -ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); /* Looks like: "ipack:fNvNdN". */ static int do_ipack_entry(const char *filename, @@ -1035,7 +962,6 @@ static int do_ipack_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); /* * Append a match expression for a single masked hex digit. @@ -1106,7 +1032,6 @@ static int do_amba_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); /* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,* * All fields are numbers. It would be nicer to use strings for vendor @@ -1131,7 +1056,6 @@ static int do_x86cpu_entry(const char *filename, void *symval, sprintf(alias + strlen(alias), "%04X*", feature); return 1; } -ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); /* LOOKS like cpu:type:*:feature:*FEAT* */ static int do_cpu_entry(const char *filename, void *symval, char *alias) @@ -1141,7 +1065,6 @@ static int do_cpu_entry(const char *filename, void *symval, char *alias) sprintf(alias, "cpu:type:*:feature:*%04X*", feature); return 1; } -ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); /* Looks like: mei:S */ static int do_mei_entry(const char *filename, void *symval, @@ -1153,7 +1076,6 @@ static int do_mei_entry(const char *filename, void *symval, return 1; } -ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) @@ -1186,6 +1108,39 @@ static void do_table(void *symval, unsigned long size, } } +static const struct devtable devtable[] = { + {"hid", SIZE_hid_device_id, do_hid_entry}, + {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry}, + {"pci", SIZE_pci_device_id, do_pci_entry}, + {"ccw", SIZE_ccw_device_id, do_ccw_entry}, + {"ap", SIZE_ap_device_id, do_ap_entry}, + {"css", SIZE_css_device_id, do_css_entry}, + {"serio", SIZE_serio_device_id, do_serio_entry}, + {"acpi", SIZE_acpi_device_id, do_acpi_entry}, + {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry}, + {"vio", SIZE_vio_device_id, do_vio_entry}, + {"input", SIZE_input_device_id, do_input_entry}, + {"eisa", SIZE_eisa_device_id, do_eisa_entry}, + {"parisc", SIZE_parisc_device_id, do_parisc_entry}, + {"sdio", SIZE_sdio_device_id, do_sdio_entry}, + {"ssb", SIZE_ssb_device_id, do_ssb_entry}, + {"bcma", SIZE_bcma_device_id, do_bcma_entry}, + {"virtio", SIZE_virtio_device_id, do_virtio_entry}, + {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry}, + {"i2c", SIZE_i2c_device_id, do_i2c_entry}, + {"spi", SIZE_spi_device_id, do_spi_entry}, + {"dmi", SIZE_dmi_system_id, do_dmi_entry}, + {"platform", SIZE_platform_device_id, do_platform_entry}, + {"mdio", SIZE_mdio_device_id, do_mdio_entry}, + {"zorro", SIZE_zorro_device_id, do_zorro_entry}, + {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry}, + {"ipack", SIZE_ipack_device_id, do_ipack_entry}, + {"amba", SIZE_amba_id, do_amba_entry}, + {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, + {"mei", SIZE_mei_cl_device_id, do_mei_entry}, + {"of", SIZE_of_device_id, do_of_entry}, +}; + /* Create MODULE_ALIAS() statements. * At this time, we cannot write the actual output C source yet, * so we write into the mod->dev_table_buf buffer. */ @@ -1194,7 +1149,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; - const char *name; + const char *name, *identifier; unsigned int namelen; /* We're looking for a section relative symbol */ @@ -1205,7 +1160,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) return; - /* All our symbols are of form __mod_XXX_device_table. */ + /* All our symbols are of form __mod____device_table. */ name = strstr(symname, "__mod_"); if (!name) return; @@ -1215,7 +1170,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, return; if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) return; - namelen -= strlen("_device_table"); + identifier = strstr(name, "__"); + if (!identifier) + return; + namelen = identifier - name; /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { @@ -1235,13 +1193,14 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, else if (sym_is(name, namelen, "pnp_card")) do_pnp_card_entries(symval, sym->st_size, mod); else { - struct devtable **p; - INIT_SECTION(__devtable); + int i; + + for (i = 0; i < ARRAY_SIZE(devtable); i++) { + const struct devtable *p = &devtable[i]; - for (p = __start___devtable; p < __stop___devtable; p++) { - if (sym_is(name, namelen, (*p)->device_id)) { - do_table(symval, sym->st_size, (*p)->id_size, - (*p)->device_id, (*p)->function, mod); + if (sym_is(name, namelen, p->device_id)) { + do_table(symval, sym->st_size, p->id_size, + p->device_id, p->function, mod); break; } } diff --git a/security/Kconfig b/security/Kconfig index 66a5f8082971a6d90dd2e9f33feddd79cd1a0d72..9735d90c0ff6b5abc367778cda1012afdf68e4d0 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -136,6 +136,37 @@ config LSM_MMAP_MIN_ADDR this low address space will need the permission specific to the systems running LSM. +config HAVE_HARDENED_USERCOPY_ALLOCATOR + bool "Harden memory copies between kernel and userspace" + help + The heap allocator implements __check_heap_object() for + validating memory ranges against heap object sizes in + support of CONFIG_HARDENED_USERCOPY. + +config HARDENED_USERCOPY + bool "Harden memory copies between kernel and userspace" + depends on HAVE_HARDENED_USERCOPY_ALLOCATOR + depends on STRICT_DEVMEM + help + This option checks for obviously wrong memory regions when + copying memory to/from the kernel (via copy_to_user() and + copy_from_user() functions) by rejecting memory ranges that + are larger than the specified heap object, span multiple + separately allocated pages, are not on the process stack, + or are part of the kernel text. This kills entire classes + of heap overflow exploits and similar kernel memory exposures. + +config HARDENED_USERCOPY_PAGESPAN + bool "Refuse to copy allocations that span multiple pages" + depends on HARDENED_USERCOPY + depends on !COMPILE_TEST + help + When a multi-page allocation is done without __GFP_COMP, + hardened usercopy will reject attempts to copy it. There are, + however, several cases of this in the kernel that have not all + been removed. This config is intended to be used only while + trying to find such users. + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig diff --git a/security/keys/key.c b/security/keys/key.c index c0d553d032c2c8b9b4776dc19d6d90291f0222f8..248c2e731375c74cae08a1d4e37c807217c0eb15 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -909,16 +909,6 @@ error: } } - key = key_ref_to_ptr(key_ref); - if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { - ret = wait_for_key_construction(key, true); - if (ret < 0) { - key_ref_put(key_ref); - key_ref = ERR_PTR(ret); - goto error_free_prep; - } - } - key_ref = __key_update(key_ref, &prep); goto error_free_prep; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 626533313cf57f7976e9da136f791ad8c71cae80..cd23eff1a00f42b8d0290deb1c401e615e9f1fdb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3333,6 +3333,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, case F_GETLK: case F_SETLK: case F_SETLKW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: #if BITS_PER_LONG == 32 case F_GETLK64: case F_SETLK64: diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 965caf8d4e8a19293b12908ad4dcbf02d9279673..44a08946fef514c5e445bb7a7d92bd089f7ec876 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 The Linux Foundation. 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 and @@ -1604,6 +1604,7 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, init_completion(&core->online_compl); init_waitqueue_head(&core->ssr_entry.offline_poll_wait); mutex_init(&core->ssr_lock); + mutex_init(&core->session_lock); core->cpe_users = 0; /* @@ -2559,6 +2560,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( * If this is the first session to be allocated, * only then register the afe service. */ + WCD_CPE_GRAB_LOCK(&core->session_lock, "session_lock"); if (!wcd_cpe_lsm_session_active()) afe_register_service = true; @@ -2570,6 +2572,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( dev_err(core->dev, "%s: max allowed sessions already allocated\n", __func__); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return NULL; } @@ -2578,6 +2581,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( dev_err(core->dev, "%s: Failed to enable cpe, err = %d\n", __func__, ret); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return NULL; } @@ -2618,6 +2622,8 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( init_completion(&session->cmd_comp); lsm_sessions[session_id] = session; + + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return session; err_afe_svc_reg: @@ -2629,6 +2635,7 @@ err_ret: err_session_alloc: wcd_cpe_vote(core, false); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return NULL; } @@ -2944,9 +2951,11 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, struct wcd_cpe_core *core = core_handle; int ret = 0; + WCD_CPE_GRAB_LOCK(&core->session_lock, "session_lock"); if (!session) { dev_err(core->dev, "%s: Invalid lsm session\n", __func__); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return -EINVAL; } @@ -2957,6 +2966,7 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, "%s: Wrong session id %d max allowed = %d\n", __func__, session->id, WCD_CPE_LSM_MAX_SESSIONS); + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return -EINVAL; } @@ -2965,21 +2975,35 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, lsm_sessions[session->id] = NULL; kfree(session); - ret = wcd_cpe_vote(core, false); - if (ret) - dev_dbg(core->dev, - "%s: Failed to un-vote cpe, err = %d\n", - __func__, ret); - if (!wcd_cpe_lsm_session_active()) { cmi_deregister(core->cmi_afe_handle); core->cmi_afe_handle = NULL; wcd_cpe_deinitialize_afe_port_data(); } + ret = wcd_cpe_vote(core, false); + if (ret) + dev_dbg(core->dev, + "%s: Failed to un-vote cpe, err = %d\n", + __func__, ret); + + WCD_CPE_REL_LOCK(&core->session_lock, "session_lock"); return ret; } +static int wcd_cpe_cdc_lab_enable(void *core_handle) +{ + struct wcd_cpe_core *core = (struct wcd_cpe_core *)core_handle; + int rc; + + rc = cpe_svc_toggle_lab(core->cpe_handle, true); + if (rc) + dev_err(core->dev, + "%s: lab enable failed, err = %d\n", + __func__, rc); + return rc; +} + static int slim_master_read_enable(void *core_handle, struct cpe_lsm_session *session) { diff --git a/sound/soc/codecs/wcd_cpe_core.h b/sound/soc/codecs/wcd_cpe_core.h index 050b0296b4b09ee19f93b81e6e0058dc736c133e..4a8a28caf5f7e53a46fc1b07fb617e266499736d 100644 --- a/sound/soc/codecs/wcd_cpe_core.h +++ b/sound/soc/codecs/wcd_cpe_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2018, The Linux Foundation. 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 and @@ -134,6 +134,9 @@ struct wcd_cpe_core { /* mutex to protect cpe ssr status variables */ struct mutex ssr_lock; + /* mutex to protect cpe session status variables */ + struct mutex session_lock; + /* Store the calibration data needed for cpe */ struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX]; diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index b9ea67c427ae98d2b55c8ae5570409c36eed414b..b58a5612cad13b288fe0e8ea68376136c7890e46 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -149,6 +149,11 @@ static ssize_t audio_output_latency_dbgfs_read(struct file *file, pr_err("%s: out_buffer is null\n", __func__); return 0; } + if (count < OUT_BUFFER_SIZE) { + pr_err("%s: read size %d exceeds buf size %zd\n", __func__, + OUT_BUFFER_SIZE, count); + return 0; + } snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\ out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\ out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec); @@ -202,6 +207,11 @@ static ssize_t audio_input_latency_dbgfs_read(struct file *file, pr_err("%s: in_buffer is null\n", __func__); return 0; } + if (count < IN_BUFFER_SIZE) { + pr_err("%s: read size %d exceeds buf size %zd\n", __func__, + IN_BUFFER_SIZE, count); + return 0; + } snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\ in_cont_tv.tv_sec, in_cont_tv.tv_usec); return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,