summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/device-mapper/boot.txt42
-rw-r--r--Documentation/devicetree/bindings/arm/cache.txt195
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/arm/boot/dts/qcom/Makefile1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-ion.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-ion.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-skuk.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi229
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi257
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton-ion.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi32
-rw-r--r--drivers/base/core.c39
-rw-r--r--drivers/clk/msm/clock-debug.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c18
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c17
-rw-r--r--drivers/md/dm-ioctl.c39
-rw-r--r--drivers/md/dm-table.c1
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c26
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c4
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c4
-rw-r--r--drivers/platform/msm/usb_bam.c11
-rw-r--r--drivers/soc/qcom/scm.c18
-rw-r--r--drivers/soc/qcom/secure_buffer.c4
-rw-r--r--drivers/staging/android/ion/ion_heap.c10
-rw-r--r--drivers/usb/dwc3/gadget.c13
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c2
-rw-r--r--include/linux/device-mapper.h6
-rw-r--r--include/net/cfg80211.h15
-rw-r--r--include/trace/events/power.h12
-rw-r--r--include/uapi/linux/nl80211.h8
-rw-r--r--init/Makefile1
-rw-r--r--init/do_mounts.c1
-rw-r--r--init/do_mounts.h13
-rw-r--r--init/do_mounts_dm.c425
-rw-r--r--kernel/sched/core.c2
-rw-r--r--kernel/sched/hmp.c145
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c7
-rw-r--r--net/wireless/util.c45
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.c3
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c2
45 files changed, 1537 insertions, 190 deletions
diff --git a/Documentation/device-mapper/boot.txt b/Documentation/device-mapper/boot.txt
new file mode 100644
index 000000000000..adcaad5e5e32
--- /dev/null
+++ b/Documentation/device-mapper/boot.txt
@@ -0,0 +1,42 @@
+Boot time creation of mapped devices
+===================================
+
+It is possible to configure a device mapper device to act as the root
+device for your system in two ways.
+
+The first is to build an initial ramdisk which boots to a minimal
+userspace which configures the device, then pivot_root(8) in to it.
+
+For simple device mapper configurations, it is possible to boot directly
+using the following kernel command line:
+
+dm="<name> <uuid> <ro>,table line 1,...,table line n"
+
+name = the name to associate with the device
+ after boot, udev, if used, will use that name to label
+ the device node.
+uuid = may be 'none' or the UUID desired for the device.
+ro = may be "ro" or "rw". If "ro", the device and device table will be
+ marked read-only.
+
+Each table line may be as normal when using the dmsetup tool except for
+two variations:
+1. Any use of commas will be interpreted as a newline
+2. Quotation marks cannot be escaped and cannot be used without
+ terminating the dm= argument.
+
+Unless renamed by udev, the device node created will be dm-0 as the
+first minor number for the device-mapper is used during early creation.
+
+Example
+=======
+
+- Booting to a linear array made up of user-mode linux block devices:
+
+ dm="lroot none 0, 0 4096 linear 98:16 0, 4096 4096 linear 98:32 0" \
+ root=/dev/dm-0
+
+Will boot to a rw dm-linear target of 8192 sectors split across two
+block devices identified by their major:minor numbers. After boot, udev
+will rename this target to /dev/mapper/lroot (depending on the rules).
+No uuid was assigned.
diff --git a/Documentation/devicetree/bindings/arm/cache.txt b/Documentation/devicetree/bindings/arm/cache.txt
new file mode 100644
index 000000000000..a9594f026506
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cache.txt
@@ -0,0 +1,195 @@
+==========================================
+ARM processors cache binding description
+==========================================
+
+Device tree bindings for ARM processor caches adhere to the cache bindings
+described in [3], in section 3.8 for multi-level and shared caches.
+On ARM based systems most of the cache properties related to cache
+geometry are probeable in HW, hence, unless otherwise stated, the properties
+defined in ePAPR for multi-level and shared caches are to be considered
+optional by default.
+
+On ARM, caches are either architected (directly controlled by the processor
+through coprocessor instructions and tightly coupled with the processor
+implementation) or unarchitected (controlled through a memory mapped
+interface, implemented as a stand-alone IP external to the processor
+implementation).
+
+This document provides the device tree bindings for ARM architected caches.
+
+- ARM architected cache node
+
+ Description: must be a direct child of the cpu node. A system
+ can contain multiple architected cache nodes per cpu node,
+ linked through the next-level-cache phandle. The
+ next-level-cache property in the cpu node points to
+ the first level of architected cache for the CPU.
+ The next-level-cache property in architected cache nodes
+ points to the respective next level of caching in the
+ hierarchy. An architected cache node with an empty or
+ missing next-level-cache property represents the last
+ architected cache level for the CPU.
+ On ARM v7 and v8 architectures, the order in which cache
+ nodes are linked through the next-level-cache phandle must
+ follow the ordering specified in the processors CLIDR (v7)
+ and CLIDR_EL1 (v8) registers, as described in [1][2],
+ implying that a cache node pointed at by a
+ next-level-cache phandle must correspond to a level
+ defined in CLIDR (v7) and CLIDR_EL1 (v8) greater than the
+ one the cache node containing the next-level-cache
+ phandle corresponds to.
+
+ Since on ARM most of the cache properties are probeable in HW the
+ properties described in [3] - section 3.8 multi-level and shared
+ caches - shall be considered optional, with the following properties
+ updates, specific for the ARM architected cache node.
+
+ - compatible
+ Usage: Required
+ Value type: <string>
+ Definition: value shall be "arm,arch-cache".
+
+ - interrupts
+ Usage: Optional
+ Value type: See definition
+ Definition: standard device tree property [3] that defines
+ the interrupt line associated with the cache.
+ The property can be accompanied by an
+ interrupt-names property, as described in [4].
+
+ - power-domain
+ Usage: Optional
+ Value type: phandle
+ Definition: A phandle and power domain specifier as defined by
+ bindings of power controller specified by the
+ phandle [5].
+
+ - qcom,dump-size
+ Usage: Optional
+ Value type: <integer>
+ Definition: The memory size needed to contain a copy of the
+ cache data and associated tag ram.
+ size = nways * nsets * (bytes per cache line +
+ bytes tag ram per line)
+
+Example(dual-cluster big.LITTLE system 32-bit)
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x0>;
+ next-level-cache = <&L1_0>;
+
+ L1_0: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_0>;
+ };
+
+ L2_0: l2-cache {
+ compatible = "arm,arch-cache";
+ };
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x1>;
+ next-level-cache = <&L1_1>;
+
+ L1_1: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_0>;
+ };
+ };
+
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x2>;
+ next-level-cache = <&L1_2>;
+
+ L1_2: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_0>;
+ };
+ };
+
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x3>;
+ next-level-cache = <&L1_3>;
+
+ L1_3: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_0>;
+ };
+ };
+
+ cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x100>;
+ next-level-cache = <&L1_4>;
+
+ L1_4: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_1>;
+ };
+
+ L2_1: l2-cache {
+ compatible = "arm,arch-cache";
+ };
+ };
+
+ cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x101>;
+ next-level-cache = <&L1_5>;
+
+ L1_5: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_1>;
+ };
+ };
+
+ cpu@102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x102>;
+ next-level-cache = <&L1_6>;
+
+ L1_6: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_1>;
+ };
+ };
+
+ cpu@103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x103>;
+ next-level-cache = <&L1_7>;
+
+ L1_7: l1-cache {
+ compatible = "arm,arch-cache";
+ next-level-cache = <&L2_1>;
+ };
+ };
+ };
+
+[1] ARMv7-AR Reference Manual
+ http://infocenter.arm.com/help/index.jsp
+[2] ARMv8-A Reference Manual
+ http://infocenter.arm.com/help/index.jsp
+[3] ePAPR standard
+ https://www.power.org/documentation/epapr-version-1-1/
+[4] Kernel documentation - resource property bindings
+ Documentation/devicetree/bindings/resource-names.txt
+[5] Kernel documentation - power domain bindings
+ Documentation/devicetree/bindings/power/power_domain.txt
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 024bdaf9af46..276d3f68e08d 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -56,6 +56,7 @@ parameter is applicable:
BLACKFIN Blackfin architecture is enabled.
CLK Common clock infrastructure is enabled.
CMA Contiguous Memory Area support is enabled.
+ DM Device mapper support is enabled.
DRM Direct Rendering Management support is enabled.
DYNAMIC_DEBUG Build in debug messages and enable them at runtime
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
@@ -919,6 +920,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
dis_ucode_ldr [X86] Disable the microcode loader.
+ dm= [DM] Allows early creation of a device-mapper device.
+ See Documentation/device-mapper/boot.txt.
+
dma_debug=off If the kernel is compiled with DMA_API_DEBUG support,
this option disables the debugging code at boot.
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index f884e0ece735..9fa8763fb19d 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -113,6 +113,7 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \
msmcobalt-v2-cdp.dtb \
msmcobalt-v2-qrd.dtb \
msmcobalt-qrd-skuk.dtb \
+ msmcobalt-v2-qrd-skuk.dtb \
msmcobalt-qrd-vr1.dtb \
msmcobalt-v2-qrd-vr1.dtb \
apqcobalt-mtp.dtb \
diff --git a/arch/arm/boot/dts/qcom/msm8996-ion.dtsi b/arch/arm/boot/dts/qcom/msm8996-ion.dtsi
index 6b64e9b8976a..9b287e3f23c5 100644
--- a/arch/arm/boot/dts/qcom/msm8996-ion.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 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
@@ -21,11 +21,6 @@
qcom,ion-heap-type = "SYSTEM";
};
- system_contig_heap: qcom,ion-heap@21 {
- reg = <21>;
- qcom,ion-heap-type = "SYSTEM_CONTIG";
- };
-
qcom,ion-heap@22 { /* ADSP HEAP */
reg = <22>;
memory-region = <&adsp_mem>;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-ion.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-ion.dtsi
index dfa3dae8e371..7b15fd81c710 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-ion.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-ion.dtsi
@@ -21,11 +21,6 @@
qcom,ion-heap-type = "SYSTEM";
};
- system_contig_heap: qcom,ion-heap@21 {
- reg = <21>;
- qcom,ion-heap-type = "SYSTEM_CONTIG";
- };
-
qcom,ion-heap@22 { /* ADSP HEAP */
reg = <22>;
memory-region = <&adsp_mem>;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi
index b77bab712ecf..81f53f1512fd 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi
@@ -100,6 +100,16 @@
};
&pmcobalt_gpios {
+ /* GPIO 2 for Home Key */
+ gpio@c100 {
+ status = "okay";
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,out-strength = <1>;
+ };
+
/* GPIO 6 for Vol+ Key */
gpio@c500 {
status = "okay";
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-skuk.dts b/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-skuk.dts
new file mode 100644
index 000000000000..78e810b816c9
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-skuk.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 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
+ * 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.
+ */
+
+
+/dts-v1/;
+
+#include "msmcobalt-v2.dtsi"
+#include "msmcobalt-qrd-skuk.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM COBALT V2 SKUK";
+ compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd";
+ qcom,board-id = <0x01000b 0x80>;
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
index 60b514c7ca20..b58e2d2c7cc6 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
@@ -2222,6 +2222,16 @@
qcom,sensors = <8>;
};
+ qcom,qbt1000 {
+ compatible = "qcom,qbt1000";
+ clock-names = "core", "iface";
+ clocks = <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>,
+ <&clock_gcc clk_gcc_blsp2_ahb_clk>;
+ clock-frequency = <15000000>;
+ qcom,ipc-gpio = <&tlmm 121 0>;
+ qcom,finger-detect-gpio = <&pmcobalt_gpios 2 0>;
+ };
+
qcom,sensor-information {
compatible = "qcom,sensor-information";
sensor_information0: qcom,sensor-information-0 {
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi
new file mode 100644
index 000000000000..61764a095a29
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 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
+ * 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 "msmfalcon-pinctrl.dtsi"
+
+/ {
+ aliases {
+ spi1 = &spi_1;
+ spi2 = &spi_2;
+ spi3 = &spi_3;
+ spi4 = &spi_4;
+ spi5 = &spi_5;
+ spi6 = &spi_6;
+ spi7 = &spi_7;
+ spi8 = &spi_8;
+ };
+};
+
+
+&soc {
+ spi_1: spi@c175000 { /* BLSP1 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc175000 0x600>,
+ <0xc144000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <4>;
+ qcom,bam-producer-pipe-index = <5>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_1_active>;
+ pinctrl-1 = <&spi_1_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>,
+ <&clock_gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_2: spi@c176000 { /* BLSP1 QUP2 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc176000 0x600>,
+ <0xc144000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 96 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <6>;
+ qcom,bam-producer-pipe-index = <7>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_2_active>;
+ pinctrl-1 = <&spi_2_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>,
+ <&clock_gcc GCC_BLSP1_QUP2_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_3: spi@c177000 { /* BLSP1 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc177000 0x600>,
+ <0xc144000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 97 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <8>;
+ qcom,bam-producer-pipe-index = <9>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_3_active>;
+ pinctrl-1 = <&spi_3_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>,
+ <&clock_gcc GCC_BLSP1_QUP3_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_4: spi@c178000 { /* BLSP1 QUP4 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc178000 0x600>,
+ <0xc144000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 98 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <10>;
+ qcom,bam-producer-pipe-index = <11>;
+ qcom,master-id = <86>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_4_active>;
+ pinctrl-1 = <&spi_4_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>,
+ <&clock_gcc GCC_BLSP1_QUP4_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_5: spi@c1b5000 { /* BLSP2 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc1b5000 0x600>,
+ <0xc184000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 101 0>, <0 239 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <4>;
+ qcom,bam-producer-pipe-index = <5>;
+ qcom,master-id = <84>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_5_active>;
+ pinctrl-1 = <&spi_5_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>,
+ <&clock_gcc GCC_BLSP2_QUP1_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_6: spi@c1b6000 { /* BLSP2 QUP2 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc1b6000 0x600>,
+ <0xc184000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 102 0>, <0 239 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <6>;
+ qcom,bam-producer-pipe-index = <7>;
+ qcom,master-id = <84>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_6_active>;
+ pinctrl-1 = <&spi_6_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>,
+ <&clock_gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_7: spi@c1b7000 { /* BLSP2 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc1b7000 0x600>,
+ <0xc184000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 103 0>, <0 239 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <8>;
+ qcom,bam-producer-pipe-index = <9>;
+ qcom,master-id = <84>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_7_active>;
+ pinctrl-1 = <&spi_7_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>,
+ <&clock_gcc GCC_BLSP2_QUP3_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+
+ spi_8: spi@c1b8000 { /* BLSP2 QUP4 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xc1b8000 0x600>,
+ <0xc184000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 104 0>, <0 239 0>;
+ spi-max-frequency = <50000000>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <10>;
+ qcom,bam-producer-pipe-index = <11>;
+ qcom,master-id = <84>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_8_active>;
+ pinctrl-1 = <&spi_8_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>,
+ <&clock_gcc GCC_BLSP2_QUP4_SPI_APPS_CLK>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi
index f6deef335844..00b9e61d01b8 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi
@@ -21,11 +21,6 @@
qcom,ion-heap-type = "SYSTEM";
};
- system_contig_heap: qcom,ion-heap@21 {
- reg = <21>;
- qcom,ion-heap-type = "SYSTEM_CONTIG";
- };
-
qcom,ion-heap@22 { /* ADSP HEAP */
reg = <22>;
memory-region = <&adsp_mem>;
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
index e8c66871425d..f13e34f8296b 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
@@ -112,5 +112,262 @@
bias-pull-down; /* pull down */
};
};
+
+ /* SPI CONFIGURATION */
+ spi_1 {
+ spi_1_active: spi_1_active {
+ mux {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ function = "blsp_spi1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_1_sleep: spi_1_sleep {
+ mux {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ function = "blsp_spi1";
+ };
+
+ config {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_2 {
+ spi_2_active: spi_2_active {
+ mux {
+ pins = "gpio4", "gpio5",
+ "gpio6", "gpio7";
+ function = "blsp_spi2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5",
+ "gpio6", "gpio7";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_2_sleep: spi_2_sleep {
+ mux {
+ pins = "gpio4", "gpio5",
+ "gpio6", "gpio7";
+ function = "blsp_spi2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5",
+ "gpio6", "gpio7";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_3 {
+ spi_3_active: spi_3_active {
+ mux {
+ pins = "gpio8", "gpio9",
+ "gpio10", "gpio11";
+ function = "blsp_spi3";
+ };
+
+ config {
+ pins = "gpio8", "gpio9",
+ "gpio10", "gpio11";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_3_sleep: spi_3_sleep {
+ mux {
+ pins = "gpio8", "gpio9",
+ "gpio10", "gpio11";
+ function = "blsp_spi3";
+ };
+
+ config {
+ pins = "gpio8", "gpio9",
+ "gpio10", "gpio11";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_4 {
+ spi_4_active: spi_4_active {
+ mux {
+ pins = "gpio12", "gpio13",
+ "gpio14", "gpio15";
+ function = "blsp_spi4";
+ };
+
+ config {
+ pins = "gpio12", "gpio13",
+ "gpio14", "gpio15";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_4_sleep: spi_4_sleep {
+ mux {
+ pins = "gpio12", "gpio13",
+ "gpio14", "gpio15";
+ function = "blsp_spi4";
+ };
+
+ config {
+ pins = "gpio12", "gpio13",
+ "gpio14", "gpio15";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_5 {
+ spi_5_active: spi_5_active {
+ mux {
+ pins = "gpio16", "gpio17",
+ "gpio18", "gpio19";
+ function = "blsp_spi5";
+ };
+
+ config {
+ pins = "gpio16", "gpio17",
+ "gpio18", "gpio19";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_5_sleep: spi_5_sleep {
+ mux {
+ pins = "gpio16", "gpio17",
+ "gpio18", "gpio19";
+ function = "blsp_spi5";
+ };
+
+ config {
+ pins = "gpio16", "gpio17",
+ "gpio18", "gpio19";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_6 {
+ spi_6_active: spi_6_active {
+ mux {
+ pins = "gpio49", "gpio52",
+ "gpio22", "gpio23";
+ function = "blsp_spi6";
+ };
+
+ config {
+ pins = "gpio49", "gpio52",
+ "gpio22", "gpio23";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_6_sleep: spi_6_sleep {
+ mux {
+ pins = "gpio49", "gpio52",
+ "gpio22", "gpio23";
+ function = "blsp_spi6";
+ };
+
+ config {
+ pins = "gpio49", "gpio52",
+ "gpio22", "gpio23";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_7 {
+ spi_7_active: spi_7_active {
+ mux {
+ pins = "gpio24", "gpio25",
+ "gpio26", "gpio27";
+ function = "blsp_spi7";
+ };
+
+ config {
+ pins = "gpio24", "gpio25",
+ "gpio26", "gpio27";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_7_sleep: spi_7_sleep {
+ mux {
+ pins = "gpio24", "gpio25",
+ "gpio26", "gpio27";
+ function = "blsp_spi7";
+ };
+
+ config {
+ pins = "gpio24", "gpio25",
+ "gpio26", "gpio27";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ spi_8 {
+ spi_8_active: spi_8_active {
+ mux {
+ pins = "gpio28", "gpio29",
+ "gpio30", "gpio31";
+ function = "blsp_spi8";
+ };
+
+ config {
+ pins = "gpio28", "gpio29",
+ "gpio30", "gpio31";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_8_sleep: spi_8_sleep {
+ mux {
+ pins = "gpio28", "gpio29",
+ "gpio30", "gpio31";
+ function = "blsp_spi8";
+ };
+
+ config {
+ pins = "gpio28", "gpio29",
+ "gpio30", "gpio31";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 7a5d83a12bfa..f2adc32fb732 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -899,3 +899,4 @@
#include "msm-pm2falcon.dtsi"
#include "msm-arm-smmu-falcon.dtsi"
#include "msm-arm-smmu-impl-defs-falcon.dtsi"
+#include "msmfalcon-blsp.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msmtriton-ion.dtsi b/arch/arm/boot/dts/qcom/msmtriton-ion.dtsi
index f6deef335844..00b9e61d01b8 100644
--- a/arch/arm/boot/dts/qcom/msmtriton-ion.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton-ion.dtsi
@@ -21,11 +21,6 @@
qcom,ion-heap-type = "SYSTEM";
};
- system_contig_heap: qcom,ion-heap@21 {
- reg = <21>;
- qcom,ion-heap-type = "SYSTEM_CONTIG";
- };
-
qcom,ion-heap@22 { /* ADSP HEAP */
reg = <22>;
memory-region = <&adsp_mem>;
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index 807c40fcc46e..8374d27e5b56 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -41,59 +41,59 @@
#address-cells = <2>;
#size-cells = <0>;
- CPU0: cpu@0 {
+ CPU0: cpu@100 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x0>;
+ reg = <0x0 0x100>;
enable-method = "psci";
};
- CPU1: cpu@1 {
+ CPU1: cpu@101 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x1>;
+ reg = <0x0 0x101>;
enable-method = "psci";
};
- CPU2: cpu@2 {
+ CPU2: cpu@102 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x2>;
+ reg = <0x0 0x102>;
enable-method = "psci";
};
- CPU3: cpu@3 {
+ CPU3: cpu@103 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x3>;
+ reg = <0x0 0x103>;
enable-method = "psci";
};
- CPU4: cpu@100 {
+ CPU4: cpu@0 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x100>;
+ reg = <0x0 0x0>;
enable-method = "psci";
};
- CPU5: cpu@101 {
+ CPU5: cpu@1 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x101>;
+ reg = <0x0 0x1>;
enable-method = "psci";
};
- CPU6: cpu@102 {
+ CPU6: cpu@2 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x102>;
+ reg = <0x0 0x2>;
enable-method = "psci";
};
- CPU7: cpu@103 {
+ CPU7: cpu@3 {
device_type = "cpu";
compatible = "arm,armv8";
- reg = <0x0 0x103>;
+ reg = <0x0 0x3>;
enable-method = "psci";
};
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 3ac683dff7de..bbe8e2efc677 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -841,11 +841,29 @@ static struct kobject *get_device_parent(struct device *dev,
return NULL;
}
+static inline bool live_in_glue_dir(struct kobject *kobj,
+ struct device *dev)
+{
+ if (!kobj || !dev->class ||
+ kobj->kset != &dev->class->p->glue_dirs)
+ return false;
+ return true;
+}
+
+static inline struct kobject *get_glue_dir(struct device *dev)
+{
+ return dev->kobj.parent;
+}
+
+/*
+ * make sure cleaning up dir as the last step, we need to make
+ * sure .release handler of kobject is run with holding the
+ * global lock
+ */
static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
{
/* see if we live in a "glue" directory */
- if (!glue_dir || !dev->class ||
- glue_dir->kset != &dev->class->p->glue_dirs)
+ if (!live_in_glue_dir(glue_dir, dev))
return;
mutex_lock(&gdp_mutex);
@@ -853,11 +871,6 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
mutex_unlock(&gdp_mutex);
}
-static void cleanup_device_parent(struct device *dev)
-{
- cleanup_glue_dir(dev, dev->kobj.parent);
-}
-
static int device_add_class_symlinks(struct device *dev)
{
struct device_node *of_node = dev_of_node(dev);
@@ -1033,6 +1046,7 @@ int device_add(struct device *dev)
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL;
+ struct kobject *glue_dir = NULL;
dev = get_device(dev);
if (!dev)
@@ -1077,8 +1091,10 @@ int device_add(struct device *dev)
/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
- if (error)
+ if (error) {
+ glue_dir = get_glue_dir(dev);
goto Error;
+ }
/* notify platform of device entry */
if (platform_notify)
@@ -1159,9 +1175,10 @@ done:
device_remove_file(dev, &dev_attr_uevent);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
+ glue_dir = get_glue_dir(dev);
kobject_del(&dev->kobj);
Error:
- cleanup_device_parent(dev);
+ cleanup_glue_dir(dev, glue_dir);
put_device(parent);
name_error:
kfree(dev->p);
@@ -1237,6 +1254,7 @@ EXPORT_SYMBOL_GPL(put_device);
void device_del(struct device *dev)
{
struct device *parent = dev->parent;
+ struct kobject *glue_dir = NULL;
struct class_interface *class_intf;
/* Notify clients of device removal. This call must come
@@ -1281,8 +1299,9 @@ void device_del(struct device *dev)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_REMOVED_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
- cleanup_device_parent(dev);
+ glue_dir = get_glue_dir(dev);
kobject_del(&dev->kobj);
+ cleanup_glue_dir(dev, glue_dir);
put_device(parent);
}
EXPORT_SYMBOL_GPL(device_del);
diff --git a/drivers/clk/msm/clock-debug.c b/drivers/clk/msm/clock-debug.c
index d0ff821eb203..00a86ba55171 100644
--- a/drivers/clk/msm/clock-debug.c
+++ b/drivers/clk/msm/clock-debug.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2014, 2016, 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
@@ -355,8 +355,12 @@ static int trace_clocks_show(struct seq_file *m, void *unused)
return 1;
}
list_for_each_entry(c, &clk_list, list) {
+ int vlevel = 0;
+
+ if (c->num_fmax)
+ vlevel = find_vdd_level(c, c->rate);
trace_clock_state(c->dbg_name, c->prepare_count, c->count,
- c->rate);
+ c->rate, vlevel);
total_cnt++;
}
mutex_unlock(&clk_list_lock);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 766b052ade1d..294444d5f59e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -792,11 +792,14 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
- if (IS_ERR(drvdata->usbch)) {
+ if (IS_ERR_OR_NULL(drvdata->usbch)) {
dev_err(drvdata->dev, "usb_qdss_open failed\n");
ret = PTR_ERR(drvdata->usbch);
pm_runtime_put(drvdata->dev);
mutex_unlock(&drvdata->mem_lock);
+ if (!ret)
+ ret = -ENODEV;
+
return ret;
}
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETB ||
@@ -1846,12 +1849,13 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
struct device_node *np = adev->dev.of_node;
struct coresight_cti_data *ctidata;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- adev->dev.platform_data = pdata;
- }
+ if (!np)
+ return -ENODEV;
+
+ pdata = of_get_coresight_platform_data(dev, np);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ adev->dev.platform_data = pdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 325bdb35e8a3..51fd79f101c8 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -58,6 +58,7 @@
#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
#define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
#define FLASH_LED_ENABLE_MASK GENMASK(2, 0)
+#define FLASH_HW_STROBE_MASK GENMASK(2, 0)
#define FLASH_LED_SAFETY_TMR_MASK GENMASK(7, 0)
#define FLASH_LED_INT_RT_STS_MASK GENMASK(7, 0)
#define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
@@ -72,7 +73,7 @@
#define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0)
#define FLASH_LED_THERMAL_OTST_MASK GENMASK(2, 0)
#define FLASH_LED_MOD_CTRL_MASK BIT(7)
-#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2)
+#define FLASH_LED_HW_SW_STROBE_SEL_BIT BIT(2)
#define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
#define FLASH_LED_LMH_MITIGATION_EN_MASK BIT(0)
#define FLASH_LED_CHGR_MITIGATION_EN_MASK BIT(4)
@@ -811,7 +812,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
}
}
- if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) {
+ if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, false);
if (rc < 0) {
@@ -831,7 +832,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
{
struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
int rc, i, addr_offset;
- u8 val;
+ u8 val, mask;
if (snode->enabled == on) {
dev_warn(&led->pdev->dev, "Switch node is already %s!\n",
@@ -869,9 +870,13 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
continue;
addr_offset = led->fnode[i].id;
+ if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT)
+ mask = FLASH_HW_STROBE_MASK;
+ else
+ mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
- FLASH_LED_ENABLE_MASK, led->fnode[i].trigger);
+ mask, led->fnode[i].trigger);
if (rc < 0)
return rc;
@@ -899,7 +904,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
}
}
- if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) {
+ if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, true);
if (rc < 0) {
@@ -1389,7 +1394,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high;
- if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) {
+ if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
fnode->hw_strobe_gpio = of_get_named_gpio(node,
"qcom,hw-strobe-gpio", 0);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 80a439543259..bc5e9a5b1f30 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1923,6 +1923,45 @@ void dm_interface_exit(void)
dm_hash_exit();
}
+
+/**
+ * dm_ioctl_export - Permanently export a mapped device via the ioctl interface
+ * @md: Pointer to mapped_device
+ * @name: Buffer (size DM_NAME_LEN) for name
+ * @uuid: Buffer (size DM_UUID_LEN) for uuid or NULL if not desired
+ */
+int dm_ioctl_export(struct mapped_device *md, const char *name,
+ const char *uuid)
+{
+ int r = 0;
+ struct hash_cell *hc;
+
+ if (!md) {
+ r = -ENXIO;
+ goto out;
+ }
+
+ /* The name and uuid can only be set once. */
+ mutex_lock(&dm_hash_cells_mutex);
+ hc = dm_get_mdptr(md);
+ mutex_unlock(&dm_hash_cells_mutex);
+ if (hc) {
+ DMERR("%s: already exported", dm_device_name(md));
+ r = -ENXIO;
+ goto out;
+ }
+
+ r = dm_hash_insert(name, uuid, md);
+ if (r) {
+ DMERR("%s: could not bind to '%s'", dm_device_name(md), name);
+ goto out;
+ }
+
+ /* Let udev know we've changed. */
+ dm_kobject_uevent(md, KOBJ_CHANGE, dm_get_event_nr(md));
+out:
+ return r;
+}
/**
* dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers
* @md: Pointer to mapped_device
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index cb5d0daf53bb..b3d78bba3a79 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
#include <linux/namei.h>
+#include <linux/mount.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index e0d6977b24a6..106d76aae3bb 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -2344,21 +2344,19 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
return -EINVAL;
}
- if (!new_frame->partial_frame_indicator) {
- if (cpp_frame_msg[new_frame->msg_len - 1] !=
- MSM_CPP_MSG_ID_TRAILER) {
- pr_err("Invalid frame message\n");
- return -EINVAL;
- }
+ if (cpp_frame_msg[new_frame->msg_len - 1] !=
+ MSM_CPP_MSG_ID_TRAILER) {
+ pr_err("Invalid frame message\n");
+ return -EINVAL;
+ }
- if ((stripe_base + new_frame->num_strips * stripe_size + 1) !=
- new_frame->msg_len) {
- pr_err("Invalid frame message,len=%d,expected=%d\n",
- new_frame->msg_len,
- (stripe_base +
- new_frame->num_strips * stripe_size + 1));
- return -EINVAL;
- }
+ if ((stripe_base + new_frame->num_strips * stripe_size + 1) !=
+ new_frame->msg_len) {
+ pr_err("Invalid frame message,len=%d,expected=%d\n",
+ new_frame->msg_len,
+ (stripe_base +
+ new_frame->num_strips * stripe_size + 1));
+ return -EINVAL;
}
if (cpp_dev->iommu_state != CPP_IOMMU_STATE_ATTACHED) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 3671d5fa6479..e612c6ed11c7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3705,6 +3705,10 @@ static void log_frame(struct msm_vidc_inst *inst, struct vidc_frame_data *data,
if (msm_comm_scale_clocks(inst->core))
dprintk(VIDC_WARN,
"Failed to scale clocks. Performance might be impacted\n");
+
+ if (msm_comm_vote_bus(inst->core))
+ dprintk(VIDC_WARN,
+ "Failed to scale bus. Performance might be impacted\n");
}
static int request_seq_header(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index efb90c69881f..011941c6d4eb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -157,7 +157,7 @@ struct dentry *msm_vidc_debugfs_init_drv(void)
struct dentry *f = debugfs_create_##__type(__name, S_IRUGO | S_IWUSR, \
dir, __value); \
if (IS_ERR_OR_NULL(f)) { \
- dprintk(VIDC_ERR, "Failed creating debugfs file '%pKd/%s'\n", \
+ dprintk(VIDC_ERR, "Failed creating debugfs file '%pd/%s'\n", \
dir, __name); \
f = NULL; \
} \
@@ -349,7 +349,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst);
goto failed_create_dir;
}
- snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst);
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
dir = debugfs_create_dir(debugfs_name, parent);
if (!dir) {
dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 43188c9d690e..5cb017fdf2d3 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -1323,6 +1323,9 @@ static void usb_bam_finish_suspend(enum usb_ctrl cur_bam)
__func__, ret);
goto no_lpm;
}
+ } else {
+ log_event_err("%s: pipe type is not B2B\n", __func__);
+ cons_empty = true;
}
spin_lock(&usb_bam_ipa_handshake_info_lock);
@@ -1959,8 +1962,8 @@ static void usb_bam_finish_resume(struct work_struct *w)
spin_unlock(&usb_bam_ipa_handshake_info_lock);
mutex_unlock(&info[cur_bam].suspend_resume_mutex);
- log_event_dbg("%s: done..PM Runtime PUT %d, count: %d\n",
- __func__, idx, get_pm_runtime_counter(bam_dev));
+ log_event_dbg("%s: done..PM Runtime PUT :%d\n",
+ __func__, get_pm_runtime_counter(bam_dev));
/* Put to match _get at the beginning of this routine */
pm_runtime_put(&ctx->usb_bam_pdev->dev);
}
@@ -2762,16 +2765,14 @@ static void usb_bam_sps_events(enum sps_callback_case sps_cb_case, void *user)
log_event_dbg("%s: received SPS_CALLBACK_BAM_TIMER_IRQ\n",
__func__);
- spin_lock(&ctx->usb_bam_lock);
-
bam = get_bam_type_from_core_name((char *)user);
if (bam < 0 || bam >= MAX_BAMS) {
log_event_err("%s: Invalid bam, type=%d ,name=%s\n",
__func__, bam, (char *)user);
- spin_unlock(&ctx->usb_bam_lock);
return;
}
ctx = &msm_usb_bam[bam];
+ spin_lock(&ctx->usb_bam_lock);
ctx->is_bam_inactivity = true;
log_event_dbg("%s: Inactivity happened on bam=%s,%d\n",
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 714c848ec9c0..b4713ac1b68b 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -56,9 +56,16 @@ DEFINE_MUTEX(scm_lmh_lock);
#define SMC_ATOMIC_MASK 0x80000000
#define IS_CALL_AVAIL_CMD 1
-#define SCM_BUF_LEN(__cmd_size, __resp_size) \
- (sizeof(struct scm_command) + sizeof(struct scm_response) + \
- __cmd_size + __resp_size)
+#define SCM_BUF_LEN(__cmd_size, __resp_size) ({ \
+ size_t x = __cmd_size + __resp_size; \
+ size_t y = sizeof(struct scm_command) + sizeof(struct scm_response); \
+ size_t result; \
+ if (x < __cmd_size || (x + y) < x) \
+ result = 0; \
+ else \
+ result = x + y; \
+ result; \
+ })
/**
* struct scm_command - one SCM command buffer
* @len: total available memory for command and response
@@ -356,8 +363,7 @@ int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
int ret;
size_t len = SCM_BUF_LEN(cmd_len, resp_len);
- if (cmd_len > scm_buf_len || resp_len > scm_buf_len ||
- len > scm_buf_len)
+ if (len == 0)
return -EINVAL;
if (!IS_ALIGNED((unsigned long)scm_buf, PAGE_SIZE))
@@ -780,7 +786,7 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
int ret;
size_t len = SCM_BUF_LEN(cmd_len, resp_len);
- if (cmd_len > len || resp_len > len)
+ if (len == 0 || PAGE_ALIGN(len) < len)
return -EINVAL;
cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index d9ebc1edda9c..afe6b2309e27 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -52,7 +52,7 @@ struct mem_prot_info {
struct dest_vm_and_perm_info {
u32 vm;
u32 perm;
- u32 *ctx;
+ u64 ctx;
u32 ctx_size;
};
@@ -209,7 +209,7 @@ populate_dest_info(int *dest_vmids, int nelements, int *dest_perms,
for (i = 0; i < nelements; i++) {
dest_info[i].vm = dest_vmids[i];
dest_info[i].perm = dest_perms[i];
- dest_info[i].ctx = NULL;
+ dest_info[i].ctx = 0x0;
dest_info[i].ctx_size = 0;
}
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index b8bf80f02f4c..43d3f92cd418 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -2,7 +2,7 @@
* drivers/staging/android/ion/ion_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2016, 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
@@ -325,8 +325,9 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
switch (heap_data->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
- heap = ion_system_contig_heap_create(heap_data);
- break;
+ pr_err("%s: Heap type is disabled: %d\n", __func__,
+ heap_data->type);
+ return ERR_PTR(-EINVAL);
case ION_HEAP_TYPE_SYSTEM:
heap = ion_system_heap_create(heap_data);
break;
@@ -366,7 +367,8 @@ void ion_heap_destroy(struct ion_heap *heap)
switch (heap->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
- ion_system_contig_heap_destroy(heap);
+ pr_err("%s: Heap type is disabled: %d\n", __func__,
+ heap->type);
break;
case ION_HEAP_TYPE_SYSTEM:
ion_system_heap_destroy(heap);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 687d51e25d4b..f32c23e97c70 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2130,24 +2130,11 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
- pm_runtime_get_sync(dwc->dev);
- dbg_event(0xFF, "Stop gsync",
- atomic_read(&dwc->dev->power.usage_count));
- dwc3_gadget_disable_irq(dwc);
spin_lock_irqsave(&dwc->lock, flags);
-
- __dwc3_gadget_ep_disable(dwc->eps[0]);
- __dwc3_gadget_ep_disable(dwc->eps[1]);
-
dwc->gadget_driver = NULL;
-
spin_unlock_irqrestore(&dwc->lock, flags);
- pm_runtime_mark_last_busy(dwc->dev);
- pm_runtime_put_autosuspend(dwc->dev);
- dbg_event(0xFF, "Auto_susgsync", 0);
-
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 0316f4e86d39..bcd23d3c19f2 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -2703,7 +2703,9 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
* enabling ahead of unblank. for some special cases like
* adb shell stop/start.
*/
+ mutex_lock(&mfd->bl_lock);
mdss_fb_set_backlight(mfd, 0);
+ mutex_unlock(&mfd->bl_lock);
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 010b5ad2ac5d..5c720864db89 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -383,6 +383,12 @@ void dm_set_mdptr(struct mapped_device *md, void *ptr);
void *dm_get_mdptr(struct mapped_device *md);
/*
+ * Export the device via the ioctl interface (uses mdptr).
+ */
+int dm_ioctl_export(struct mapped_device *md, const char *name,
+ const char *uuid);
+
+/*
* A device can still be used while suspended, but I/O is deferred.
*/
int dm_suspend(struct mapped_device *md, unsigned suspend_flags);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 35c527c7d2e4..b89c9c2f7f6e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -796,11 +796,19 @@ struct cfg80211_csa_settings {
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
+ * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
+ * the GCD of a single value is considered the value itself, so for
+ * a single interface this should be set to that interface's beacon
+ * interval
+ * @beacon_int_different: a flag indicating whether or not all beacon
+ * intervals (of beaconing interfaces) are different or not.
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
};
/**
@@ -2894,6 +2902,12 @@ struct ieee80211_iface_limit {
* only in special cases.
* @radar_detect_widths: bitmap of channel widths supported for radar detection
* @radar_detect_regions: bitmap of regions supported for radar detection
+ * @beacon_int_min_gcd: This interface combination supports different
+ * beacon intervals.
+ * = 0 - all beacon intervals for different interface must be same.
+ * > 0 - any beacon interval for the interface part of this combination AND
+ * *GCD* of all beacon intervals from beaconing interfaces of this
+ * combination must be greater or equal to this value.
*
* With this structure the driver can describe which interface
* combinations it supports concurrently.
@@ -2952,6 +2966,7 @@ struct ieee80211_iface_combination {
bool beacon_int_infra_match;
u8 radar_detect_widths;
u8 radar_detect_regions;
+ u32 beacon_int_min_gcd;
};
struct ieee80211_txrx_stypes {
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index e8bc27f3467e..bc33e91ec5e6 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -369,15 +369,17 @@ TRACE_EVENT(clock_set_parent,
TRACE_EVENT(clock_state,
TP_PROTO(const char *name, unsigned long prepare_count,
- unsigned long count, unsigned long rate),
+ unsigned long count, unsigned long rate,
+ unsigned int vdd_level),
- TP_ARGS(name, prepare_count, count, rate),
+ TP_ARGS(name, prepare_count, count, rate, vdd_level),
TP_STRUCT__entry(
__string(name, name)
__field(unsigned long, prepare_count)
__field(unsigned long, count)
__field(unsigned long, rate)
+ __field(unsigned int, vdd_level)
),
TP_fast_assign(
@@ -385,10 +387,12 @@ TRACE_EVENT(clock_state,
__entry->prepare_count = prepare_count;
__entry->count = count;
__entry->rate = rate;
+ __entry->vdd_level = vdd_level;
),
- TP_printk("%s\t[%lu:%lu]\t%lu", __get_str(name), __entry->prepare_count,
- __entry->count, __entry->rate)
+ TP_printk("%s\tprepare:enable cnt [%lu:%lu]\trate: vdd level [%lu:%u]",
+ __get_str(name), __entry->prepare_count,
+ __entry->count, __entry->rate, __entry->vdd_level)
);
/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 5305e8f4fce1..696a4322844a 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4101,6 +4101,9 @@ enum nl80211_iface_limit_attrs {
* of supported channel widths for radar detection.
* @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
* of supported regulatory regions for radar detection.
+ * @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of
+ * different beacon intervals supported by all the interface combinations
+ * in this group (if not present, all beacon intervals be identical).
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -4108,8 +4111,8 @@ enum nl80211_iface_limit_attrs {
* limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
* => allows an AP and a STA that must match BIs
*
- * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
- * => allows 8 of AP/GO
+ * numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8,
+ * => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels
@@ -4135,6 +4138,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
+ NL80211_IFACE_COMB_BI_MIN_GCD,
/* keep last */
NUM_NL80211_IFACE_COMB,
diff --git a/init/Makefile b/init/Makefile
index 692b91f1c1d4..243f61de2cba 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -15,6 +15,7 @@ mounts-y := do_mounts.o
mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o
mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o
mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o
+mounts-$(CONFIG_BLK_DEV_DM) += do_mounts_dm.o
# dependencies on generated files need to be listed explicitly
$(obj)/version.o: include/generated/compile.h
diff --git a/init/do_mounts.c b/init/do_mounts.c
index dea5de95c2dd..1902a1c80831 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -566,6 +566,7 @@ void __init prepare_namespace(void)
wait_for_device_probe();
md_run_setup();
+ dm_run_setup();
if (saved_root_name[0]) {
root_device_name = saved_root_name;
diff --git a/init/do_mounts.h b/init/do_mounts.h
index 375835f1d258..09d22862e8c3 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -13,9 +13,6 @@ void mount_block_root(char *name, int flags);
void mount_root(void);
extern int root_mountflags;
-struct dm_table;
-static inline void dm_table_put(struct dm_table *t) { }
-
static inline int create_dev(char *name, dev_t dev)
{
sys_unlink(name);
@@ -77,3 +74,13 @@ void md_run_setup(void);
static inline void md_run_setup(void) {}
#endif
+
+#ifdef CONFIG_BLK_DEV_DM
+
+void dm_run_setup(void);
+
+#else
+
+static inline void dm_run_setup(void) {}
+
+#endif
diff --git a/init/do_mounts_dm.c b/init/do_mounts_dm.c
new file mode 100644
index 000000000000..f521bc5ae248
--- /dev/null
+++ b/init/do_mounts_dm.c
@@ -0,0 +1,425 @@
+/* do_mounts_dm.c
+ * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ * All Rights Reserved.
+ * Based on do_mounts_md.c
+ *
+ * This file is released under the GPL.
+ */
+#include <linux/device-mapper.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include "do_mounts.h"
+#include "../drivers/md/dm.h"
+
+#define DM_MAX_NAME 32
+#define DM_MAX_UUID 129
+#define DM_NO_UUID "none"
+
+#define DM_MSG_PREFIX "init"
+
+/* Separators used for parsing the dm= argument. */
+#define DM_FIELD_SEP ' '
+#define DM_LINE_SEP ','
+
+/*
+ * When the device-mapper and any targets are compiled into the kernel
+ * (not a module), one target may be created and used as the root device at
+ * boot time with the parameters given with the boot line dm=...
+ * The code for that is here.
+ */
+
+struct dm_setup_target {
+ sector_t begin;
+ sector_t length;
+ char *type;
+ char *params;
+ /* simple singly linked list */
+ struct dm_setup_target *next;
+};
+
+static struct {
+ int minor;
+ int ro;
+ char name[DM_MAX_NAME];
+ char uuid[DM_MAX_UUID];
+ char *targets;
+ struct dm_setup_target *target;
+ int target_count;
+} dm_setup_args __initdata;
+
+static __initdata int dm_early_setup;
+
+static size_t __init get_dm_option(char *str, char **next, char sep)
+{
+ size_t len = 0;
+ char *endp = NULL;
+
+ if (!str)
+ return 0;
+
+ endp = strchr(str, sep);
+ if (!endp) { /* act like strchrnul */
+ len = strlen(str);
+ endp = str + len;
+ } else {
+ len = endp - str;
+ }
+
+ if (endp == str)
+ return 0;
+
+ if (!next)
+ return len;
+
+ if (*endp == 0) {
+ /* Don't advance past the nul. */
+ *next = endp;
+ } else {
+ *next = endp + 1;
+ }
+ return len;
+}
+
+static int __init dm_setup_args_init(void)
+{
+ dm_setup_args.minor = 0;
+ dm_setup_args.ro = 0;
+ dm_setup_args.target = NULL;
+ dm_setup_args.target_count = 0;
+ return 0;
+}
+
+static int __init dm_setup_cleanup(void)
+{
+ struct dm_setup_target *target = dm_setup_args.target;
+ struct dm_setup_target *old_target = NULL;
+ while (target) {
+ kfree(target->type);
+ kfree(target->params);
+ old_target = target;
+ target = target->next;
+ kfree(old_target);
+ dm_setup_args.target_count--;
+ }
+ BUG_ON(dm_setup_args.target_count);
+ return 0;
+}
+
+static char * __init dm_setup_parse_device_args(char *str)
+{
+ char *next = NULL;
+ size_t len = 0;
+
+ /* Grab the logical name of the device to be exported to udev */
+ len = get_dm_option(str, &next, DM_FIELD_SEP);
+ if (!len) {
+ DMERR("failed to parse device name");
+ goto parse_fail;
+ }
+ len = min(len + 1, sizeof(dm_setup_args.name));
+ strlcpy(dm_setup_args.name, str, len); /* includes nul */
+ str = skip_spaces(next);
+
+ /* Grab the UUID value or "none" */
+ len = get_dm_option(str, &next, DM_FIELD_SEP);
+ if (!len) {
+ DMERR("failed to parse device uuid");
+ goto parse_fail;
+ }
+ len = min(len + 1, sizeof(dm_setup_args.uuid));
+ strlcpy(dm_setup_args.uuid, str, len);
+ str = skip_spaces(next);
+
+ /* Determine if the table/device will be read only or read-write */
+ if (!strncmp("ro,", str, 3)) {
+ dm_setup_args.ro = 1;
+ } else if (!strncmp("rw,", str, 3)) {
+ dm_setup_args.ro = 0;
+ } else {
+ DMERR("failed to parse table mode");
+ goto parse_fail;
+ }
+ str = skip_spaces(str + 3);
+
+ return str;
+
+parse_fail:
+ return NULL;
+}
+
+static void __init dm_substitute_devices(char *str, size_t str_len)
+{
+ char *candidate = str;
+ char *candidate_end = str;
+ char old_char;
+ size_t len = 0;
+ dev_t dev;
+
+ if (str_len < 3)
+ return;
+
+ while (str && *str) {
+ candidate = strchr(str, '/');
+ if (!candidate)
+ break;
+
+ /* Avoid embedded slashes */
+ if (candidate != str && *(candidate - 1) != DM_FIELD_SEP) {
+ str = strchr(candidate, DM_FIELD_SEP);
+ continue;
+ }
+
+ len = get_dm_option(candidate, &candidate_end, DM_FIELD_SEP);
+ str = skip_spaces(candidate_end);
+ if (len < 3 || len > 37) /* name_to_dev_t max; maj:mix min */
+ continue;
+
+ /* Temporarily terminate with a nul */
+ candidate_end--;
+ old_char = *candidate_end;
+ *candidate_end = '\0';
+
+ DMDEBUG("converting candidate device '%s' to dev_t", candidate);
+ /* Use the boot-time specific device naming */
+ dev = name_to_dev_t(candidate);
+ *candidate_end = old_char;
+
+ DMDEBUG(" -> %u", dev);
+ /* No suitable replacement found */
+ if (!dev)
+ continue;
+
+ /* Rewrite the /dev/path as a major:minor */
+ len = snprintf(candidate, len, "%u:%u", MAJOR(dev), MINOR(dev));
+ if (!len) {
+ DMERR("error substituting device major/minor.");
+ break;
+ }
+ candidate += len;
+ /* Pad out with spaces (fixing our nul) */
+ while (candidate < candidate_end)
+ *(candidate++) = DM_FIELD_SEP;
+ }
+}
+
+static int __init dm_setup_parse_targets(char *str)
+{
+ char *next = NULL;
+ size_t len = 0;
+ struct dm_setup_target **target = NULL;
+
+ /* Targets are defined as per the table format but with a
+ * comma as a newline separator. */
+ target = &dm_setup_args.target;
+ while (str && *str) {
+ *target = kzalloc(sizeof(struct dm_setup_target), GFP_KERNEL);
+ if (!*target) {
+ DMERR("failed to allocate memory for target %d",
+ dm_setup_args.target_count);
+ goto parse_fail;
+ }
+ dm_setup_args.target_count++;
+
+ (*target)->begin = simple_strtoull(str, &next, 10);
+ if (!next || *next != DM_FIELD_SEP) {
+ DMERR("failed to parse starting sector for target %d",
+ dm_setup_args.target_count - 1);
+ goto parse_fail;
+ }
+ str = skip_spaces(next + 1);
+
+ (*target)->length = simple_strtoull(str, &next, 10);
+ if (!next || *next != DM_FIELD_SEP) {
+ DMERR("failed to parse length for target %d",
+ dm_setup_args.target_count - 1);
+ goto parse_fail;
+ }
+ str = skip_spaces(next + 1);
+
+ len = get_dm_option(str, &next, DM_FIELD_SEP);
+ if (!len ||
+ !((*target)->type = kstrndup(str, len, GFP_KERNEL))) {
+ DMERR("failed to parse type for target %d",
+ dm_setup_args.target_count - 1);
+ goto parse_fail;
+ }
+ str = skip_spaces(next);
+
+ len = get_dm_option(str, &next, DM_LINE_SEP);
+ if (!len ||
+ !((*target)->params = kstrndup(str, len, GFP_KERNEL))) {
+ DMERR("failed to parse params for target %d",
+ dm_setup_args.target_count - 1);
+ goto parse_fail;
+ }
+ str = skip_spaces(next);
+
+ /* Before moving on, walk through the copied target and
+ * attempt to replace all /dev/xxx with the major:minor number.
+ * It may not be possible to resolve them traditionally at
+ * boot-time. */
+ dm_substitute_devices((*target)->params, len);
+
+ target = &((*target)->next);
+ }
+ DMDEBUG("parsed %d targets", dm_setup_args.target_count);
+
+ return 0;
+
+parse_fail:
+ return 1;
+}
+
+/*
+ * Parse the command-line parameters given our kernel, but do not
+ * actually try to invoke the DM device now; that is handled by
+ * dm_setup_drive after the low-level disk drivers have initialised.
+ * dm format is as follows:
+ * dm="name uuid fmode,[table line 1],[table line 2],..."
+ * May be used with root=/dev/dm-0 as it always uses the first dm minor.
+ */
+
+static int __init dm_setup(char *str)
+{
+ dm_setup_args_init();
+
+ str = dm_setup_parse_device_args(str);
+ if (!str) {
+ DMDEBUG("str is NULL");
+ goto parse_fail;
+ }
+
+ /* Target parsing is delayed until we have dynamic memory */
+ dm_setup_args.targets = str;
+
+ printk(KERN_INFO "dm: will configure '%s' on dm-%d\n",
+ dm_setup_args.name, dm_setup_args.minor);
+
+ dm_early_setup = 1;
+ return 1;
+
+parse_fail:
+ printk(KERN_WARNING "dm: Invalid arguments supplied to dm=.\n");
+ return 0;
+}
+
+
+static void __init dm_setup_drive(void)
+{
+ struct mapped_device *md = NULL;
+ struct dm_table *table = NULL;
+ struct dm_setup_target *target;
+ char *uuid = dm_setup_args.uuid;
+ fmode_t fmode = FMODE_READ;
+
+ /* Finish parsing the targets. */
+ if (dm_setup_parse_targets(dm_setup_args.targets))
+ goto parse_fail;
+
+ if (dm_create(dm_setup_args.minor, &md)) {
+ DMDEBUG("failed to create the device");
+ goto dm_create_fail;
+ }
+ DMDEBUG("created device '%s'", dm_device_name(md));
+
+ /* In addition to flagging the table below, the disk must be
+ * set explicitly ro/rw. */
+ set_disk_ro(dm_disk(md), dm_setup_args.ro);
+
+ if (!dm_setup_args.ro)
+ fmode |= FMODE_WRITE;
+ if (dm_table_create(&table, fmode, dm_setup_args.target_count, md)) {
+ DMDEBUG("failed to create the table");
+ goto dm_table_create_fail;
+ }
+
+ dm_lock_md_type(md);
+ target = dm_setup_args.target;
+ while (target) {
+ DMINFO("adding target '%llu %llu %s %s'",
+ (unsigned long long) target->begin,
+ (unsigned long long) target->length, target->type,
+ target->params);
+ if (dm_table_add_target(table, target->type, target->begin,
+ target->length, target->params)) {
+ DMDEBUG("failed to add the target to the table");
+ goto add_target_fail;
+ }
+ target = target->next;
+ }
+
+ if (dm_table_complete(table)) {
+ DMDEBUG("failed to complete the table");
+ goto table_complete_fail;
+ }
+
+ if (dm_get_md_type(md) == DM_TYPE_NONE) {
+ dm_set_md_type(md, dm_table_get_type(table));
+ if (dm_setup_md_queue(md)) {
+ DMWARN("unable to set up device queue for new table.");
+ goto setup_md_queue_fail;
+ }
+ } else if (dm_get_md_type(md) != dm_table_get_type(table)) {
+ DMWARN("can't change device type after initial table load.");
+ goto setup_md_queue_fail;
+ }
+
+ /* Suspend the device so that we can bind it to the table. */
+ if (dm_suspend(md, 0)) {
+ DMDEBUG("failed to suspend the device pre-bind");
+ goto suspend_fail;
+ }
+
+ /* Bind the table to the device. This is the only way to associate
+ * md->map with the table and set the disk capacity directly. */
+ if (dm_swap_table(md, table)) { /* should return NULL. */
+ DMDEBUG("failed to bind the device to the table");
+ goto table_bind_fail;
+ }
+
+ /* Finally, resume and the device should be ready. */
+ if (dm_resume(md)) {
+ DMDEBUG("failed to resume the device");
+ goto resume_fail;
+ }
+
+ /* Export the dm device via the ioctl interface */
+ if (!strcmp(DM_NO_UUID, dm_setup_args.uuid))
+ uuid = NULL;
+ if (dm_ioctl_export(md, dm_setup_args.name, uuid)) {
+ DMDEBUG("failed to export device with given name and uuid");
+ goto export_fail;
+ }
+ printk(KERN_INFO "dm: dm-%d is ready\n", dm_setup_args.minor);
+
+ dm_unlock_md_type(md);
+ dm_setup_cleanup();
+ return;
+
+export_fail:
+resume_fail:
+table_bind_fail:
+suspend_fail:
+setup_md_queue_fail:
+table_complete_fail:
+add_target_fail:
+ dm_unlock_md_type(md);
+dm_table_create_fail:
+ dm_put(md);
+dm_create_fail:
+ dm_setup_cleanup();
+parse_fail:
+ printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n",
+ dm_setup_args.minor, dm_setup_args.name);
+}
+
+__setup("dm=", dm_setup);
+
+void __init dm_run_setup(void)
+{
+ if (!dm_early_setup)
+ return;
+ printk(KERN_INFO "dm: attempting early device configuration.\n");
+ dm_setup_drive();
+}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index c07d844c576e..f3b1688b3be7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2572,8 +2572,8 @@ void wake_up_new_task(struct task_struct *p)
unsigned long flags;
struct rq *rq;
- raw_spin_lock_irqsave(&p->pi_lock, flags);
add_new_task_to_grp(p);
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
/* Initialize new task's runnable average */
init_entity_runnable_average(&p->se);
#ifdef CONFIG_SMP
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 1d55e226196f..56f4c60d4d5d 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -1396,16 +1396,6 @@ void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra)
}
}
-/*
- * Invoked from three places:
- * 1) try_to_wake_up() -> ... -> select_best_cpu()
- * 2) scheduler_tick() -> ... -> migration_needed() -> select_best_cpu()
- * 3) can_migrate_task()
- *
- * Its safe to de-reference p->grp in first case (since p->pi_lock is held)
- * but not in other cases. p->grp is hence freed after a RCU grace period and
- * accessed under rcu_read_lock()
- */
int preferred_cluster(struct sched_cluster *cluster, struct task_struct *p)
{
struct related_thread_group *grp;
@@ -3883,7 +3873,12 @@ static void _set_preferred_cluster(struct related_thread_group *grp)
void set_preferred_cluster(struct related_thread_group *grp)
{
- raw_spin_lock(&grp->lock);
+ /*
+ * Prevent possible deadlock with update_children(). Not updating
+ * the preferred cluster once is not a big deal.
+ */
+ if (!raw_spin_trylock(&grp->lock))
+ return;
_set_preferred_cluster(grp);
raw_spin_unlock(&grp->lock);
}
@@ -3904,7 +3899,7 @@ static int alloc_group_cputime(struct related_thread_group *grp)
struct rq *rq = cpu_rq(cpu);
u64 window_start = rq->window_start;
- grp->cpu_time = alloc_percpu(struct group_cpu_time);
+ grp->cpu_time = alloc_percpu_gfp(struct group_cpu_time, GFP_ATOMIC);
if (!grp->cpu_time)
return -ENOMEM;
@@ -4088,7 +4083,7 @@ struct related_thread_group *alloc_related_thread_group(int group_id)
{
struct related_thread_group *grp;
- grp = kzalloc(sizeof(*grp), GFP_KERNEL);
+ grp = kzalloc(sizeof(*grp), GFP_ATOMIC);
if (!grp)
return ERR_PTR(-ENOMEM);
@@ -4127,19 +4122,64 @@ static void free_related_thread_group(struct rcu_head *rcu)
kfree(grp);
}
+/*
+ * The thread group for a task can change while we are here. However,
+ * add_new_task_to_grp() will take care of any tasks that we miss here.
+ * When a parent exits, and a child thread is simultaneously exiting,
+ * sched_set_group_id() will synchronize those operations.
+ */
+static void update_children(struct task_struct *leader,
+ struct related_thread_group *grp, int event)
+{
+ struct task_struct *child;
+ struct rq *rq;
+ unsigned long flags;
+
+ if (!thread_group_leader(leader))
+ return;
+
+ if (event == ADD_TASK && !sysctl_sched_enable_thread_grouping)
+ return;
+
+ if (thread_group_empty(leader))
+ return;
+
+ child = next_thread(leader);
+
+ do {
+ rq = task_rq_lock(child, &flags);
+
+ if (event == REM_TASK && child->grp && grp == child->grp) {
+ transfer_busy_time(rq, grp, child, event);
+ list_del_init(&child->grp_list);
+ rcu_assign_pointer(child->grp, NULL);
+ } else if (event == ADD_TASK && !child->grp) {
+ transfer_busy_time(rq, grp, child, event);
+ list_add(&child->grp_list, &grp->tasks);
+ rcu_assign_pointer(child->grp, grp);
+ }
+
+ task_rq_unlock(rq, child, &flags);
+ } while_each_thread(leader, child);
+
+}
+
static void remove_task_from_group(struct task_struct *p)
{
struct related_thread_group *grp = p->grp;
struct rq *rq;
int empty_group = 1;
+ unsigned long flags;
raw_spin_lock(&grp->lock);
- rq = __task_rq_lock(p);
+ rq = task_rq_lock(p, &flags);
transfer_busy_time(rq, p->grp, p, REM_TASK);
list_del_init(&p->grp_list);
rcu_assign_pointer(p->grp, NULL);
- __task_rq_unlock(rq);
+ task_rq_unlock(rq, p, &flags);
+
+ update_children(p, grp, REM_TASK);
if (!list_empty(&grp->tasks)) {
empty_group = 0;
@@ -4158,6 +4198,7 @@ static int
add_task_to_group(struct task_struct *p, struct related_thread_group *grp)
{
struct rq *rq;
+ unsigned long flags;
raw_spin_lock(&grp->lock);
@@ -4165,11 +4206,13 @@ add_task_to_group(struct task_struct *p, struct related_thread_group *grp)
* Change p->grp under rq->lock. Will prevent races with read-side
* reference of p->grp in various hot-paths
*/
- rq = __task_rq_lock(p);
+ rq = task_rq_lock(p, &flags);
transfer_busy_time(rq, grp, p, ADD_TASK);
list_add(&p->grp_list, &grp->tasks);
rcu_assign_pointer(p->grp, grp);
- __task_rq_unlock(rq);
+ task_rq_unlock(rq, p, &flags);
+
+ update_children(p, grp, ADD_TASK);
_set_preferred_cluster(grp);
@@ -4192,82 +4235,62 @@ void add_new_task_to_grp(struct task_struct *new)
parent = new->group_leader;
- /*
- * The parent's pi_lock is required here to protect race
- * against the parent task being removed from the
- * group.
- */
- raw_spin_lock_irqsave(&parent->pi_lock, flags);
+ write_lock_irqsave(&related_thread_group_lock, flags);
- /* protected by pi_lock. */
+ rcu_read_lock();
grp = task_related_thread_group(parent);
- if (!grp) {
- raw_spin_unlock_irqrestore(&parent->pi_lock, flags);
+ rcu_read_unlock();
+
+ /* Its possible that update_children() already added us to the group */
+ if (!grp || new->grp) {
+ write_unlock_irqrestore(&related_thread_group_lock, flags);
return;
}
+
raw_spin_lock(&grp->lock);
rcu_assign_pointer(new->grp, grp);
list_add(&new->grp_list, &grp->tasks);
raw_spin_unlock(&grp->lock);
- raw_spin_unlock_irqrestore(&parent->pi_lock, flags);
+ write_unlock_irqrestore(&related_thread_group_lock, flags);
}
int sched_set_group_id(struct task_struct *p, unsigned int group_id)
{
- int rc = 0, destroy = 0;
+ int rc = 0;
unsigned long flags;
- struct related_thread_group *grp = NULL, *new = NULL;
+ struct related_thread_group *grp = NULL;
-redo:
- raw_spin_lock_irqsave(&p->pi_lock, flags);
+ /* Prevents tasks from exiting while we are managing groups. */
+ write_lock_irqsave(&related_thread_group_lock, flags);
+ /* Switching from one group to another directly is not permitted */
if ((current != p && p->flags & PF_EXITING) ||
(!p->grp && !group_id) ||
- (p->grp && p->grp->id == group_id))
+ (p->grp && group_id))
goto done;
- write_lock(&related_thread_group_lock);
-
if (!group_id) {
remove_task_from_group(p);
- write_unlock(&related_thread_group_lock);
goto done;
}
- if (p->grp && p->grp->id != group_id)
- remove_task_from_group(p);
-
grp = lookup_related_thread_group(group_id);
- if (!grp && !new) {
- /* New group */
- write_unlock(&related_thread_group_lock);
- raw_spin_unlock_irqrestore(&p->pi_lock, flags);
- new = alloc_related_thread_group(group_id);
- if (IS_ERR(new))
- return -ENOMEM;
- destroy = 1;
- /* Rerun checks (like task exiting), since we dropped pi_lock */
- goto redo;
- } else if (!grp && new) {
- /* New group - use object allocated before */
- destroy = 0;
- list_add(&new->list, &related_thread_groups);
- grp = new;
+ if (!grp) {
+ grp = alloc_related_thread_group(group_id);
+ if (IS_ERR(grp)) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ list_add(&grp->list, &related_thread_groups);
}
BUG_ON(!grp);
rc = add_task_to_group(p, grp);
- write_unlock(&related_thread_group_lock);
done:
- raw_spin_unlock_irqrestore(&p->pi_lock, flags);
-
- if (new && destroy) {
- free_group_cputime(new);
- kfree(new);
- }
-
+ write_unlock_irqrestore(&related_thread_group_lock, flags);
return rc;
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 05125d092b18..fcd59e76a8e5 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -466,7 +466,7 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
u32 *mask);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- u32 beacon_int);
+ enum nl80211_iftype iftype, u32 beacon_int);
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4d7281df26b6..40299f19c09b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1003,6 +1003,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
c->radar_detect_regions)))
goto nla_put_failure;
+ if (c->beacon_int_min_gcd &&
+ nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
+ c->beacon_int_min_gcd))
+ goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
@@ -3656,7 +3660,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
- err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
+ params.beacon_interval);
if (err)
return err;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6822b4e57fad..acff02fcc281 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1483,24 +1483,46 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- u32 beacon_int)
+ enum nl80211_iftype iftype, u32 beacon_int)
{
struct wireless_dev *wdev;
- int res = 0;
+ struct iface_combination_params params = {
+ .beacon_int_gcd = beacon_int, /* GCD(n) = n */
+ };
if (!beacon_int)
return -EINVAL;
+ params.iftype_num[iftype] = 1;
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
- if (wdev->beacon_interval != beacon_int) {
- res = -EINVAL;
- break;
+
+ params.iftype_num[wdev->iftype]++;
+ }
+
+ list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ u32 bi_prev = wdev->beacon_interval;
+
+ if (!wdev->beacon_interval)
+ continue;
+
+ /* slight optimisation - skip identical BIs */
+ if (wdev->beacon_interval == beacon_int)
+ continue;
+
+ params.beacon_int_different = true;
+
+ /* Get the GCD */
+ while (bi_prev != 0) {
+ u32 tmp_bi = bi_prev;
+
+ bi_prev = params.beacon_int_gcd % bi_prev;
+ params.beacon_int_gcd = tmp_bi;
}
}
- return res;
+ return cfg80211_check_combinations(&rdev->wiphy, &params);
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@@ -1576,6 +1598,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
+ if (params->beacon_int_gcd) {
+ if (c->beacon_int_min_gcd &&
+ params->beacon_int_gcd < c->beacon_int_min_gcd) {
+ kfree(limits);
+ return -EINVAL;
+ }
+ if (!c->beacon_int_min_gcd &&
+ params->beacon_int_different)
+ goto cont;
+ }
+
/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index 64c33c082b4b..5dbdb9a2df00 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -1015,6 +1015,7 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec,
0;
}
+ (*mbhc) = wcd934x_mbhc;
snd_soc_add_codec_controls(codec, impedance_detect_controls,
ARRAY_SIZE(impedance_detect_controls));
snd_soc_add_codec_controls(codec, hph_type_detect_controls,
@@ -1023,8 +1024,6 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec,
snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
- (*mbhc) = wcd934x_mbhc;
-
return 0;
err:
devm_kfree(codec->dev, wcd934x_mbhc);
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 5d6119c6d86a..d77217892f12 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -5136,7 +5136,7 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
snd_soc_update_bits(codec, WCD934X_SOC_MAD_INP_SEL,
0x0F, tavil_mad_input);
snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
- 0x03, mic_bias_found);
+ 0x07, mic_bias_found);
return 0;
}