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=" ,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: + 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: + 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,62 +41,62 @@ #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x0>; - enable-method = "psci"; - }; - - CPU1: cpu@1 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x1>; - enable-method = "psci"; - }; - - CPU2: cpu@2 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x2>; - enable-method = "psci"; - }; - - CPU3: cpu@3 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x3>; - enable-method = "psci"; - }; - - CPU4: cpu@100 { + CPU0: cpu@100 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; }; - CPU5: cpu@101 { + CPU1: cpu@101 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x101>; enable-method = "psci"; }; - CPU6: cpu@102 { + CPU2: cpu@102 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x102>; enable-method = "psci"; }; - CPU7: cpu@103 { + CPU3: cpu@103 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x103>; enable-method = "psci"; }; + CPU4: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + CPU5: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + }; + + CPU6: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + CPU7: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + cpu-map { cluster0 { core0 { 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 #include #include +#include #include #include #include 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 @@ -382,6 +382,12 @@ void dm_put(struct mapped_device *md); 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. */ 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 + * All Rights Reserved. + * Based on do_mounts_md.c + * + * This file is released under the GPL. + */ +#include +#include +#include + +#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, ¶ms); } 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; }