diff options
424 files changed, 5959 insertions, 2091 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index bc0548201755..fc759598c4c9 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,4 +1,4 @@ subdir-y := accounting auxdisplay blackfin connector \ - filesystems filesystems ia64 laptops mic misc-devices \ + filesystems filesystems ia64 laptops misc-devices \ networking pcmcia prctl ptp spi timers vDSO video4linux \ watchdog diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt index 6ddc72576e88..a6537ebd2512 100644 --- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt +++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt @@ -108,6 +108,8 @@ Optional driver parameters: - qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem. - qcom,pil-force-shutdown: Boolean. If set, the SSR framework will not trigger graceful shutdown on behalf of the subsystem driver. +- qcom,mdm-link-info: a string indicating additional info about the physical link. + For example: "devID_domain.bus.slot" in case of PCIe. Example: mdm0: qcom,mdm0 { diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt index 0a9b31a946ec..3688e3ebab48 100644 --- a/Documentation/devicetree/bindings/gpio/gpio_keys.txt +++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt @@ -15,6 +15,8 @@ Optional properties: config defined in pin groups of interrupt and reset gpio. "gpio_ts_suspend" : Disabled configuration of pins, this should specify sleep config defined in pin groups of interrupt and reset gpio. + - name : input device name. + - use-syscore : use syscore functionality for driver. Each button (key) is represented as a sub-node of "gpio-keys": Subnode properties: @@ -41,6 +43,7 @@ gpio_keys { pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend"; pinctrl-0 = <&gpio_key_active>; pinctrl-1 = <&gpio_key_suspend>; + use-syscore; button@21 { label = "GPIO Key UP"; linux,code = <103>; diff --git a/Documentation/devicetree/bindings/media/video/laser-sensor.txt b/Documentation/devicetree/bindings/media/video/laser-sensor.txt index 1bcb0b93cb10..0003f20845a0 100644 --- a/Documentation/devicetree/bindings/media/video/laser-sensor.txt +++ b/Documentation/devicetree/bindings/media/video/laser-sensor.txt @@ -19,6 +19,7 @@ Required node properties: regulators used - pinctrl-names : should specify the pin control groups followed by the definition of each group + stm,irq-gpio : irq gpio which is to provide interrupts to host. - gpios : should contain phandle to gpio controller node and array of #gpio-cells specifying specific gpio (controller specific) - qcom,gpio-req-tbl-num : contains index to gpios specific to the sensor diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt index c8f2a5a8e496..92ef23c3a290 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt @@ -31,6 +31,12 @@ Charger specific properties: revid module. This is used to identify the SMB subtype. +- qcom,parallel-mode + Usage: optional + Value type: <u32> + Definition: Specifies parallel charging mode. If not specified, MID-MID + option is selected by default. + - qcom,suspend-input Usage: optional Value type: <empty> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 45d680644dfe..0220f18658e8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -750,6 +750,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. seconds. Defaults to 10*60 = 10mins. A value of 0 disables the blank timer. + core_ctl_disable_cpumask= [SMP] + Exempt the CPUs from being managed by core_ctl. + core_ctl operates on a cluster basis. So all the + CPUs in a given cluster must be specified to disable + core_ctl for that cluster. + coredump_filter= [KNL] Change the default value for /proc/<pid>/coredump_filter. @@ -1265,6 +1271,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. When zero, profiling data is discarded and associated debugfs files are removed at module unload time. + goldfish [X86] Enable the goldfish android emulator platform. + Don't use this when you are not running on the + android emulator + gpt [EFI] Forces disk with valid GPT signature but invalid Protective MBR to be treated as GPT. If the primary GPT is corrupted, it enables the backup/alternate diff --git a/Documentation/mic/Makefile b/Documentation/mic/Makefile deleted file mode 100644 index a191d453badf..000000000000 --- a/Documentation/mic/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := mpssd diff --git a/Documentation/mic/mpssd/Makefile b/Documentation/mic/mpssd/Makefile deleted file mode 100644 index 06871b0c08a6..000000000000 --- a/Documentation/mic/mpssd/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -ifndef CROSS_COMPILE -# List of programs to build -hostprogs-$(CONFIG_X86_64) := mpssd - -mpssd-objs := mpssd.o sysfs.o - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -HOSTCFLAGS += -I$(objtree)/usr/include -I$(srctree)/tools/include - -ifdef DEBUG -HOSTCFLAGS += -DDEBUG=$(DEBUG) -endif - -HOSTLOADLIBES_mpssd := -lpthread - -install: - install mpssd /usr/sbin/mpssd - install micctrl /usr/sbin/micctrl -endif @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 49 +SUBLEVEL = 55 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index e74df327cdd3..20618a897c99 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -122,6 +122,8 @@ uart1: serial@f8020000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1_default>; + atmel,use-dma-rx; + atmel,use-dma-tx; status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index da84e65b56ef..e27024cdf48b 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -110,6 +110,8 @@ }; usart3: serial@fc00c000 { + atmel,use-dma-rx; + atmel,use-dma-tx; status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi index 69f24bbfc3c0..8d867bb697be 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -216,6 +216,8 @@ qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,config-select = <&dsi_dual_nt35597_truly_cmd_config0>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi index ab6266e9e6b8..1a572f97c840 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -202,6 +202,8 @@ qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; qcom,mdss-dsi-tx-eot-append; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,config-select = <&dsi_dual_nt35597_truly_video_config0>; diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi index 42cf30c789d9..d450f43f8c22 100644 --- a/arch/arm/boot/dts/qcom/msm-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi @@ -931,6 +931,8 @@ clocks = <&clock_rpmcc RPM_DIV_CLK1>; qcom,node_has_rpm_clock; #clock-cells = <1>; + qcom,codec-mclk-clk-freq = <11289600>; + qcom,mclk-clk-reg = <0x15020018 0x0>; pinctrl-names = "sleep", "active"; pinctrl-0 = <&lpi_mclk0_sleep>; pinctrl-1 = <&lpi_mclk0_active>; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3.dtsi b/arch/arm/boot/dts/qcom/msm8996-v3.dtsi index c30e19eacc69..7e5fa8a495c9 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-v3.dtsi @@ -73,6 +73,23 @@ < 315000000 4 >, < 401800000 5 >, < 510000000 5 >; + + qcom,gfxfreq-speedbin2 = + < 0 0 0 >, + < 133000000 2 4 >, + < 214000000 3 4 >, + < 315000000 4 4 >, + < 401800000 5 5 >, + < 510000000 6 5 >, + < 560000000 7 7 >; + qcom,gfxfreq-mx-speedbin2 = + < 0 0 >, + < 133000000 4 >, + < 214000000 4 >, + < 315000000 4 >, + < 401800000 5 >, + < 510000000 5 >, + < 560000000 7 >; }; &gdsc_gpu_gx { @@ -416,6 +433,23 @@ < 1190400000 11 >, < 1228800000 12 >, < 1363200000 13 >; + qcom,pwrcl-speedbin2-v0 = + < 0 0 >, + < 307200000 1 >, + < 422400000 2 >, + < 480000000 3 >, + < 556800000 4 >, + < 652800000 5 >, + < 729600000 6 >, + < 844800000 7 >, + < 960000000 8 >, + < 1036800000 9 >, + < 1113600000 10 >, + < 1190400000 11 >, + < 1228800000 12 >, + < 1324800000 13 >, + < 1401600000 14 >, + < 1497600000 15 >; qcom,perfcl-speedbin0-v0 = < 0 0 >, < 307200000 1 >, @@ -466,6 +500,30 @@ < 1708800000 19 >, < 1785600000 20 >, < 1804800000 21 >; + qcom,perfcl-speedbin2-v0 = + < 0 0 >, + < 307200000 1 >, + < 403200000 2 >, + < 480000000 3 >, + < 556800000 4 >, + < 652800000 5 >, + < 729600000 6 >, + < 806400000 7 >, + < 883200000 8 >, + < 940800000 9 >, + < 1036800000 10 >, + < 1113600000 11 >, + < 1190400000 12 >, + < 1248000000 13 >, + < 1324800000 14 >, + < 1401600000 15 >, + < 1478400000 16 >, + < 1555200000 17 >, + < 1632000000 18 >, + < 1708800000 19 >, + < 1785600000 20 >, + < 1804800000 21 >, + < 1900800000 22 >; qcom,cbf-speedbin0-v0 = < 0 0 >, < 307200000 1 >, @@ -504,6 +562,23 @@ < 1190400000 13 >, < 1228800000 14 >, < 1305600000 15 >; + qcom,cbf-speedbin2-v0 = + < 0 0 >, + < 307200000 1 >, + < 384000000 2 >, + < 460800000 3 >, + < 537600000 4 >, + < 595200000 5 >, + < 672000000 6 >, + < 748800000 7 >, + < 825600000 8 >, + < 902400000 9 >, + < 979200000 10 >, + < 1056000000 11 >, + < 1132800000 12 >, + < 1190400000 13 >, + < 1228800000 14 >, + < 1305600000 15 >; }; &msm_cpufreq { diff --git a/arch/arm/boot/dts/qcom/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi index 094a4cfbabdc..abff47ff8d58 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi @@ -956,7 +956,8 @@ < 1363200000 15 >, < 1440000000 16 >, < 1516800000 17 >, - < 1593600000 18 >; + < 1593600000 18 >, + < 1996800000 20 >; qcom,perfcl-speedbin0-v0 = < 0 0 >, < 307200000 1 >, diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi index 707eca4e9ddd..d5c8900f6e67 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi @@ -95,6 +95,7 @@ pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_tof_active>; pinctrl-1 = <&cam_tof_suspend>; + stm,irq-gpio = <&tlmm 26 0x2008>; gpios = <&tlmm 126 0>; qcom,gpio-req-tbl-num = <0>; qcom,gpio-req-tbl-flags = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi index 17dcfb560b73..2ed0f2250de5 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -79,6 +79,7 @@ pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_tof_active>; pinctrl-1 = <&cam_tof_suspend>; + stm,irq-gpio = <&tlmm 26 0x2008>; gpios = <&tlmm 126 0>; qcom,gpio-req-tbl-num = <0>; qcom,gpio-req-tbl-flags = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi index e0ba982d7932..f87444465a68 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi @@ -493,11 +493,11 @@ <&clock_mmss clk_mmss_camss_csi1_clk>, <&clock_mmss clk_mmss_camss_csi2_clk>, <&clock_mmss clk_mmss_camss_csi3_clk>, - <&clock_mmss clk_mmss_camss_vfe0_clk>, <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_mmss_camss_vfe0_clk>, <&clock_mmss clk_mmss_camss_csi_vfe0_clk>, - <&clock_mmss clk_mmss_camss_vfe1_clk>, <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_mmss_camss_vfe1_clk>, <&clock_mmss clk_mmss_camss_csi_vfe1_clk>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "camss_ahb_clk", @@ -510,10 +510,12 @@ "csi2_pix_clk", "csi3_pix_clk", "camss_csi0_clk", "camss_csi1_clk", "camss_csi2_clk", "camss_csi3_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", - "vfe0_clk_src", "camss_csi_vfe0_clk", + "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", - "vfe1_clk_src", "camss_csi_vfe1_clk"; + "camss_csi_vfe1_clk"; qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -532,10 +534,10 @@ "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", - "NO_SET_RATE", - "INIT_RATE", "NO_SET_RATE", - "NO_SET_RATE", - "INIT_RATE", "NO_SET_RATE"; + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE"; status = "ok"; }; @@ -557,23 +559,23 @@ <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, + <&clock_mmss clk_vfe0_clk_src>, <&clock_mmss clk_mmss_camss_vfe0_clk>, <&clock_mmss clk_mmss_camss_vfe0_stream_clk>, <&clock_mmss clk_mmss_camss_vfe0_ahb_clk>, <&clock_mmss clk_mmss_camss_vfe_vbif_ahb_clk>, <&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>, - <&clock_mmss clk_vfe0_clk_src>, <&clock_mmss clk_mmss_camss_csi_vfe0_clk>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", - "camss_vfe_vbif_axi_clk", "vfe_clk_src", + "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 480000000 0 - 0 0 0 0 0 0 0 0 0 0 0 576000000 0 - 0 0 0 0 0 0 0 0 0 0 0 600000000 0>; + qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 576000000 0 0 0 0 0 0 + 0 0 0 0 0 0 600000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 @@ -637,23 +639,23 @@ <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, + <&clock_mmss clk_vfe1_clk_src>, <&clock_mmss clk_mmss_camss_vfe1_clk>, <&clock_mmss clk_mmss_camss_vfe1_stream_clk>, <&clock_mmss clk_mmss_camss_vfe1_ahb_clk>, <&clock_mmss clk_mmss_camss_vfe_vbif_ahb_clk>, <&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>, - <&clock_mmss clk_vfe1_clk_src>, <&clock_mmss clk_mmss_camss_csi_vfe1_clk>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", - "camss_vfe_vbif_axi_clk", "vfe_clk_src", + "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 480000000 0 - 0 0 0 0 0 0 0 0 0 0 0 576000000 0 - 0 0 0 0 0 0 0 0 0 0 0 600000000 0>; + qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 576000000 0 0 0 0 0 0 + 0 0 0 0 0 0 600000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 diff --git a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi index 518ad33c63ea..045cdda09d18 100644 --- a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -409,6 +409,7 @@ pm8998_l24: regulator-l24 { regulator-min-microvolt = <3088000>; regulator-max-microvolt = <3088000>; + parent-supply = <&pm8998_l12>; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi index 82b9b2cf4de8..8b226586ca7b 100644 --- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi @@ -451,11 +451,11 @@ <&clock_mmss MMSS_CAMSS_CSI1_CLK>, <&clock_mmss MMSS_CAMSS_CSI2_CLK>, <&clock_mmss MMSS_CAMSS_CSI3_CLK>, - <&clock_mmss MMSS_CAMSS_VFE0_CLK>, <&clock_mmss VFE0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE0_CLK>, <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>, - <&clock_mmss MMSS_CAMSS_VFE1_CLK>, <&clock_mmss VFE1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE1_CLK>, <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "camss_ahb_clk", @@ -468,10 +468,12 @@ "csi2_pix_clk", "csi3_pix_clk", "camss_csi0_clk", "camss_csi1_clk", "camss_csi2_clk", "camss_csi3_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", - "vfe0_clk_src", "camss_csi_vfe0_clk", + "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", - "vfe1_clk_src", "camss_csi_vfe1_clk"; + "camss_csi_vfe1_clk"; qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -490,10 +492,10 @@ "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", - "NO_SET_RATE", - "INIT_RATE", "NO_SET_RATE", - "NO_SET_RATE", - "INIT_RATE", "NO_SET_RATE"; + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE"; status = "ok"; }; @@ -516,23 +518,23 @@ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, <&clock_mmss MMSS_CAMSS_AHB_CLK>, <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss VFE0_CLK_SRC>, <&clock_mmss MMSS_CAMSS_VFE0_CLK>, <&clock_mmss MMSS_CAMSS_VFE0_STREAM_CLK>, <&clock_mmss MMSS_CAMSS_VFE0_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, - <&clock_mmss VFE0_CLK_SRC>, <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", - "camss_vfe_vbif_axi_clk", "vfe_clk_src", + "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0 - 0 0 0 0 0 0 0 0 0 0 0 480000000 0 - 0 0 0 0 0 0 0 0 0 0 0 576000000 0>; + qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 @@ -597,23 +599,23 @@ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, <&clock_mmss MMSS_CAMSS_AHB_CLK>, <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss VFE1_CLK_SRC>, <&clock_mmss MMSS_CAMSS_VFE1_CLK>, <&clock_mmss MMSS_CAMSS_VFE1_STREAM_CLK>, <&clock_mmss MMSS_CAMSS_VFE1_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, - <&clock_mmss VFE1_CLK_SRC>, <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", - "camss_vfe_vbif_axi_clk", "vfe_clk_src", + "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0 - 0 0 0 0 0 0 0 0 0 0 0 480000000 0 - 0 0 0 0 0 0 0 0 0 0 0 576000000 0>; + qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 diff --git a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi index 2448e1894387..0dd2d206ddd5 100644 --- a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi @@ -132,6 +132,9 @@ qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>; + /* Enable midframe sampling */ + qcom,enable-midframe-timer; + /* GPU Mempools */ qcom,gpu-mempools { #address-cells= <1>; diff --git a/arch/arm/boot/dts/qcom/sdm630-pm.dtsi b/arch/arm/boot/dts/qcom/sdm630-pm.dtsi index 093eadab0413..b8272b29aa89 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-pm.dtsi @@ -63,20 +63,20 @@ reg = <0>; label = "system-active"; qcom,psci-mode = <0x0>; - qcom,latency-us = <100>; - qcom,ss-power = <725>; - qcom,energy-overhead = <85000>; - qcom,time-overhead = <120>; + qcom,latency-us = <50>; + qcom,ss-power = <240>; + qcom,energy-overhead = <61750>; + qcom,time-overhead = <7870>; }; qcom,pm-cluster-level@1{ /* E3 */ reg = <1>; label = "system-pc"; qcom,psci-mode = <0x3>; - qcom,latency-us = <350>; - qcom,ss-power = <530>; - qcom,energy-overhead = <160000>; - qcom,time-overhead = <550>; + qcom,latency-us = <4026>; + qcom,ss-power = <167>; + qcom,energy-overhead = <749982>; + qcom,time-overhead = <14773>; qcom,min-child-idx = <3>; qcom,is-reset; qcom,notify-rpm; @@ -96,19 +96,19 @@ reg = <0>; label = "pwr-l2-active"; qcom,psci-mode = <0x1>; - qcom,latency-us = <40>; - qcom,ss-power = <740>; - qcom,energy-overhead = <65000>; - qcom,time-overhead = <85>; + qcom,latency-us = <51>; + qcom,ss-power = <198>; + qcom,energy-overhead = <83852>; + qcom,time-overhead = <91>; }; qcom,pm-cluster-level@1{ /* D2D */ reg = <1>; label = "pwr-l2-dynret"; qcom,psci-mode = <0x2>; - qcom,latency-us = <60>; - qcom,ss-power = <700>; - qcom,energy-overhead = <85000>; - qcom,time-overhead = <85>; + qcom,latency-us = <384>; + qcom,ss-power = <197>; + qcom,energy-overhead = <198413>; + qcom,time-overhead = <668>; qcom,min-child-idx = <1>; }; @@ -116,10 +116,10 @@ reg = <2>; label = "pwr-l2-ret"; qcom,psci-mode = <0x3>; - qcom,latency-us = <100>; - qcom,ss-power = <640>; - qcom,energy-overhead = <135000>; - qcom,time-overhead = <85>; + qcom,latency-us = <423>; + qcom,ss-power = <193>; + qcom,energy-overhead = <218055>; + qcom,time-overhead = <761>; qcom,min-child-idx = <2>; }; @@ -127,10 +127,10 @@ reg = <3>; label = "pwr-l2-pc"; qcom,psci-mode = <0x4>; - qcom,latency-us = <700>; - qcom,ss-power = <450>; - qcom,energy-overhead = <210000>; - qcom,time-overhead = <11500>; + qcom,latency-us = <1821>; + qcom,ss-power = <184>; + qcom,energy-overhead = <558835>; + qcom,time-overhead = <2336>; qcom,min-child-idx = <2>; qcom,is-reset; }; @@ -145,30 +145,30 @@ reg = <0>; qcom,spm-cpu-mode = "wfi"; qcom,psci-cpu-mode = <0x1>; - qcom,latency-us = <20>; - qcom,ss-power = <750>; - qcom,energy-overhead = <32000>; - qcom,time-overhead = <60>; + qcom,latency-us = <42>; + qcom,ss-power = <240>; + qcom,energy-overhead = <30562>; + qcom,time-overhead = <91>; }; qcom,pm-cpu-level@1 { /* C2D */ reg = <1>; qcom,psci-cpu-mode = <2>; qcom,spm-cpu-mode = "ret"; - qcom,latency-us = <40>; - qcom,ss-power = <730>; - qcom,energy-overhead = <85500>; - qcom,time-overhead = <110>; + qcom,latency-us = <90>; + qcom,ss-power = <213>; + qcom,energy-overhead = <79070>; + qcom,time-overhead = <253>; }; qcom,pm-cpu-level@2 { /* C3 */ reg = <2>; qcom,spm-cpu-mode = "pc"; qcom,psci-cpu-mode = <0x3>; - qcom,latency-us = <80>; - qcom,ss-power = <700>; - qcom,energy-overhead = <126480>; - qcom,time-overhead = <160>; + qcom,latency-us = <343>; + qcom,ss-power = <200>; + qcom,energy-overhead = <170215>; + qcom,time-overhead = <605>; qcom,is-reset; }; }; @@ -188,20 +188,20 @@ reg = <0>; label = "perf-l2-active"; qcom,psci-mode = <0x1>; - qcom,latency-us = <40>; - qcom,ss-power = <740>; - qcom,energy-overhead = <70000>; - qcom,time-overhead = <80>; + qcom,latency-us = <51>; + qcom,ss-power = <287>; + qcom,energy-overhead = <61412>; + qcom,time-overhead = <89>; }; qcom,pm-cluster-level@1{ /* D2D */ reg = <1>; label = "perf-l2-dynret"; qcom,psci-mode = <2>; - qcom,latency-us = <60>; - qcom,ss-power = <700>; - qcom,energy-overhead = <85000>; - qcom,time-overhead = <85>; + qcom,latency-us = <329>; + qcom,ss-power = <284>; + qcom,energy-overhead = <206996>; + qcom,time-overhead = <601>; qcom,min-child-idx = <1>; }; @@ -209,10 +209,10 @@ reg = <2>; label = "perf-l2-ret"; qcom,psci-mode = <3>; - qcom,latency-us = <100>; - qcom,ss-power = <640>; - qcom,energy-overhead = <135000>; - qcom,time-overhead = <85>; + qcom,latency-us = <368>; + qcom,ss-power = <277>; + qcom,energy-overhead = <240450>; + qcom,time-overhead = <700>; qcom,min-child-idx = <2>; }; @@ -220,10 +220,10 @@ reg = <3>; label = "perf-l2-pc"; qcom,psci-mode = <0x4>; - qcom,latency-us = <800>; - qcom,ss-power = <450>; - qcom,energy-overhead = <240000>; - qcom,time-overhead = <11500>; + qcom,latency-us = <1609>; + qcom,ss-power = <262>; + qcom,energy-overhead = <703061>; + qcom,time-overhead = <2154>; qcom,min-child-idx = <2>; qcom,is-reset; }; @@ -238,30 +238,30 @@ reg = <0>; qcom,spm-cpu-mode = "wfi"; qcom,psci-cpu-mode = <0x1>; - qcom,latency-us = <25>; - qcom,ss-power = <750>; - qcom,energy-overhead = <37000>; - qcom,time-overhead = <50>; + qcom,latency-us = <39>; + qcom,ss-power = <315>; + qcom,energy-overhead = <37558>; + qcom,time-overhead = <83>; }; qcom,pm-cpu-level@1 { /* C2D */ reg = <1>; qcom,psci-cpu-mode = <2>; qcom,spm-cpu-mode = "ret"; - qcom,latency-us = <40>; - qcom,ss-power = <730>; - qcom,energy-overhead = <85500>; - qcom,time-overhead = <110>; + qcom,latency-us = <87>; + qcom,ss-power = <299>; + qcom,energy-overhead = <91434>; + qcom,time-overhead = <241>; }; qcom,pm-cpu-level@2 { /* C3 */ reg = <2>; qcom,spm-cpu-mode = "pc"; qcom,psci-cpu-mode = <0x3>; - qcom,latency-us = <80>; - qcom,ss-power = <700>; - qcom,energy-overhead = <136480>; - qcom,time-overhead = <160>; + qcom,latency-us = <301>; + qcom,ss-power = <291>; + qcom,energy-overhead = <199377>; + qcom,time-overhead = <563>; qcom,is-reset; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index cb083c0a8aa0..fb24f727fb49 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -197,6 +197,13 @@ status = "ok"; }; +&sdc2_cd_on { + config { + /delete-property/ bias-pull-up; + bias-disable; + }; +}; + &sdhc_2 { /* device core power supply */ vdd-supply = <&pm660l_l5>; @@ -317,6 +324,12 @@ }; }; +&ssphy { + fpc-redrive-supply = <&pm660_l11>; + qcom,redrive-voltage-level = <0 1800000 1950000>; + qcom,redrive-load = <105000>; +}; + &soc { qcom,msm-ssc-sensors { compatible = "qcom,msm-ssc-sensors"; diff --git a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi index c16c83050f31..eded8b08528a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi @@ -376,6 +376,7 @@ pm660l_l7: regulator-l7 { regulator-min-microvolt = <2700000>; regulator-max-microvolt = <3125000>; + parent-supply = <&pm660_l10>; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 623ca54de94b..9626e0548789 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -34,7 +34,7 @@ chosen { stdout-path = "serial0"; - bootargs = "rcupdate.rcu_expedited=1"; + bootargs = "rcupdate.rcu_expedited=1 core_ctl_disable_cpumask=0-7"; }; psci { @@ -1235,8 +1235,8 @@ <90 512 206000 960000>, <1 676 206000 160000>; qcom,bus-vector-names = "MIN", "SVS", "PERF", "TURBO"; - qcom,rx-polling-sleep-ms = <2>; /* Polling sleep interval */ - qcom,ipa-polling-iteration = <5>; /* Polling Iteration */ + qcom,rx-polling-sleep-ms = <1>; /* Polling sleep interval */ + qcom,ipa-polling-iteration = <40>; /* Polling Iteration */ ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; diff --git a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi index c1cb6441cd43..402f19efd50d 100644 --- a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi @@ -34,7 +34,7 @@ clock-names = "wcd_clk", "wcd_native_clk"; clocks = <&clock_audio AUDIO_PMI_CLK>, - <&clock_audio AUDIO_AP_CLK2>; + <&clock_audio AUDIO_LPASS_MCLK>; cdc-vdd-mic-bias-supply = <&pm660l_bob>; qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>; diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi index 1f886f7f368f..f3b81b5df1de 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi @@ -454,11 +454,11 @@ <&clock_mmss MMSS_CAMSS_CSI1_CLK>, <&clock_mmss MMSS_CAMSS_CSI2_CLK>, <&clock_mmss MMSS_CAMSS_CSI3_CLK>, - <&clock_mmss MMSS_CAMSS_VFE0_CLK>, <&clock_mmss VFE0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE0_CLK>, <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>, - <&clock_mmss MMSS_CAMSS_VFE1_CLK>, <&clock_mmss VFE1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE1_CLK>, <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "camss_ahb_clk", @@ -471,10 +471,12 @@ "csi2_pix_clk", "csi3_pix_clk", "camss_csi0_clk", "camss_csi1_clk", "camss_csi2_clk", "camss_csi3_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", - "vfe0_clk_src", "camss_csi_vfe0_clk", + "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", - "vfe1_clk_src", "camss_csi_vfe1_clk"; + "camss_csi_vfe1_clk"; qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -493,10 +495,10 @@ "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", - "NO_SET_RATE", - "INIT_RATE", "NO_SET_RATE", - "NO_SET_RATE", - "INIT_RATE", "NO_SET_RATE"; + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE"; status = "ok"; }; @@ -518,23 +520,23 @@ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, <&clock_mmss MMSS_CAMSS_AHB_CLK>, <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss VFE0_CLK_SRC>, <&clock_mmss MMSS_CAMSS_VFE0_CLK>, <&clock_mmss MMSS_CAMSS_VFE0_STREAM_CLK>, <&clock_mmss MMSS_CAMSS_VFE0_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, - <&clock_mmss VFE0_CLK_SRC>, <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", - "camss_vfe_vbif_axi_clk", "vfe_clk_src", + "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0 - 0 0 0 0 0 0 0 0 0 0 0 480000000 0 - 0 0 0 0 0 0 0 0 0 0 0 576000000 0>; + qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 @@ -599,23 +601,23 @@ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, <&clock_mmss MMSS_CAMSS_AHB_CLK>, <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss VFE1_CLK_SRC>, <&clock_mmss MMSS_CAMSS_VFE1_CLK>, <&clock_mmss MMSS_CAMSS_VFE1_STREAM_CLK>, <&clock_mmss MMSS_CAMSS_VFE1_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, - <&clock_mmss VFE1_CLK_SRC>, <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; clock-names = "mmssnoc_axi", "mnoc_ahb_clk", "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", - "camss_vfe_vbif_axi_clk", "vfe_clk_src", + "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0 - 0 0 0 0 0 0 0 0 0 0 0 480000000 0 - 0 0 0 0 0 0 0 0 0 0 0 576000000 0>; + qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi index a9bf6fdae72a..fbe6d1d8cc74 100644 --- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi @@ -518,6 +518,8 @@ qcom,ice-clk-rates = <300000000 75000000>; + qcom,scaling-lower-bus-speed-mode = "DDR52"; + status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index c3c776be3209..f5d61d440a27 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -141,9 +141,6 @@ qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>; - /* Enable midframe sampling */ - qcom,enable-midframe-timer; - /* GPU Mempools */ qcom,gpu-mempools { #address-cells= <1>; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index 0e869f0e1352..3d2cfedc1009 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -196,6 +196,12 @@ }; }; +&ssphy { + fpc-redrive-supply = <&pm660_l11>; + qcom,redrive-voltage-level = <0 1800000 1950000>; + qcom,redrive-load = <105000>; +}; + &soc { gpio_keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi index 462a76ef8bfe..a93efdc38f41 100644 --- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi @@ -377,6 +377,7 @@ pm660l_l7: regulator-l7 { regulator-min-microvolt = <2700000>; regulator-max-microvolt = <3125000>; + parent-supply = <&pm660_l10>; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index d16c082542d7..1e0b6136e1b4 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -1463,8 +1463,8 @@ <90 512 206000 960000>, <1 676 206000 160000>; qcom,bus-vector-names = "MIN", "SVS", "PERF", "TURBO"; - qcom,rx-polling-sleep-ms = <2>; /* Polling sleep interval */ - qcom,ipa-polling-iteration = <5>; /* Polling Iteration */ + qcom,rx-polling-sleep-ms = <1>; /* Polling sleep interval */ + qcom,ipa-polling-iteration = <40>; /* Polling Iteration */ ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index 21650ead5a34..32cf48661c9b 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -472,7 +472,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y -CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index 02b15745e882..c4b0eabe2fbf 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -471,7 +471,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y -CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index c7ba9a42e857..ebf866a3a8c8 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -205,18 +205,12 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn, * and iterate over the range. */ - bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached; - VM_BUG_ON(size & ~PAGE_MASK); - if (!need_flush && !icache_is_pipt()) - goto vipt_cache; - while (size) { void *va = kmap_atomic_pfn(pfn); - if (need_flush) - kvm_flush_dcache_to_poc(va, PAGE_SIZE); + kvm_flush_dcache_to_poc(va, PAGE_SIZE); if (icache_is_pipt()) __cpuc_coherent_user_range((unsigned long)va, @@ -228,7 +222,6 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn, kunmap_atomic(va); } -vipt_cache: if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) { /* any kind of VIPT cache */ __flush_icache_all(); diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 8ecfd15c3a02..df73914e81c8 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -67,7 +67,7 @@ ENTRY(__get_user_4) ENDPROC(__get_user_4) ENTRY(__get_user_8) - check_uaccess r0, 8, r1, r2, __get_user_bad + check_uaccess r0, 8, r1, r2, __get_user_bad8 #ifdef CONFIG_THUMB2_KERNEL 5: TUSER(ldr) r2, [r0] 6: TUSER(ldr) r3, [r0, #4] diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index b15e01bfa51b..0031c55360c7 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -438,7 +438,6 @@ CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_ECM=y CONFIG_USB_CONFIGFS_QCRNDIS=y -CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 988f1fbf8ea3..261a49d7944a 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -423,7 +423,6 @@ CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_ECM=y CONFIG_USB_CONFIGFS_QCRNDIS=y -CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig index ccf3653ee817..ccd653eaec7d 100644 --- a/arch/arm64/configs/msmcortex_mediabox_defconfig +++ b/arch/arm64/configs/msmcortex_mediabox_defconfig @@ -282,6 +282,7 @@ CONFIG_WIL6210=m CONFIG_ATH10K=m CONFIG_ATH10K_TARGET_SNOC=m CONFIG_ATH10K_SNOC=y +CONFIG_ATH10K_DEBUG=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index 7084d2098e8c..ffb983587c31 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -471,7 +471,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y -CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index 69ea4418e8d9..bba52749284a 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -474,7 +474,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y -CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y @@ -502,6 +501,7 @@ CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_EDAC_CORTEX_ARM64=y CONFIG_EDAC_CORTEX_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_CORTEX_ARM64_DBE_IRQ_ONLY=y CONFIG_EDAC_CORTEX_ARM64_PANIC_ON_UE=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 342a5ac2f3da..320dc9c7e4f4 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -237,8 +237,7 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn, { void *va = page_address(pfn_to_page(pfn)); - if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached) - kvm_flush_dcache_to_poc(va, size); + kvm_flush_dcache_to_poc(va, size); if (!icache_is_aliasing()) { /* PIPT */ flush_icache_range((unsigned long)va, diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 8cfd5ab37743..a1c2ac38771d 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -664,7 +664,7 @@ ENDPROC(__secondary_switched) */ .section ".idmap.text", "ax" ENTRY(__enable_mmu) - mrs x18, sctlr_el1 // preserve old SCTLR_EL1 value + mrs x22, sctlr_el1 // preserve old SCTLR_EL1 value mrs x1, ID_AA64MMFR0_EL1 ubfx x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4 cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED @@ -691,7 +691,7 @@ ENTRY(__enable_mmu) * to take into account by discarding the current kernel mapping and * creating a new one. */ - msr sctlr_el1, x18 // disable the MMU + msr sctlr_el1, x22 // disable the MMU isb bl __create_page_tables // recreate kernel mapping diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c index b05469173ba5..310f2f463cd4 100644 --- a/arch/arm64/kernel/kaslr.c +++ b/arch/arm64/kernel/kaslr.c @@ -130,11 +130,15 @@ u64 __init kaslr_early_init(u64 dt_phys, u64 modulo_offset) /* * The kernel Image should not extend across a 1GB/32MB/512MB alignment * boundary (for 4KB/16KB/64KB granule kernels, respectively). If this - * happens, increase the KASLR offset by the size of the kernel image. + * happens, increase the KASLR offset by the size of the kernel image + * rounded up by SWAPPER_BLOCK_SIZE. */ if ((((u64)_text + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT) != - (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT)) - offset = (offset + (u64)(_end - _text)) & mask; + (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT)) { + u64 kimg_sz = _end - _text; + offset = (offset + round_up(kimg_sz, SWAPPER_BLOCK_SIZE)) + & mask; + } if (IS_ENABLED(CONFIG_KASAN)) /* diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c index 52caa75bfe4e..e2f50d690624 100644 --- a/arch/mips/bcm47xx/buttons.c +++ b/arch/mips/bcm47xx/buttons.c @@ -17,6 +17,12 @@ .active_low = 1, \ } +#define BCM47XX_GPIO_KEY_H(_gpio, _code) \ + { \ + .code = _code, \ + .gpio = _gpio, \ + } + /* Asus */ static const struct gpio_keys_button @@ -79,8 +85,8 @@ bcm47xx_buttons_asus_wl500gpv2[] __initconst = { static const struct gpio_keys_button bcm47xx_buttons_asus_wl500w[] __initconst = { - BCM47XX_GPIO_KEY(6, KEY_RESTART), - BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON), + BCM47XX_GPIO_KEY_H(6, KEY_RESTART), + BCM47XX_GPIO_KEY_H(7, KEY_WPS_BUTTON), }; static const struct gpio_keys_button diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S index 64e08df51d65..8b7004132491 100644 --- a/arch/mips/cavium-octeon/octeon-memcpy.S +++ b/arch/mips/cavium-octeon/octeon-memcpy.S @@ -208,18 +208,18 @@ EXC( STORE t2, UNIT(6)(dst), s_exc_p10u) ADD src, src, 16*NBYTES EXC( STORE t3, UNIT(7)(dst), s_exc_p9u) ADD dst, dst, 16*NBYTES -EXC( LOAD t0, UNIT(-8)(src), l_exc_copy) -EXC( LOAD t1, UNIT(-7)(src), l_exc_copy) -EXC( LOAD t2, UNIT(-6)(src), l_exc_copy) -EXC( LOAD t3, UNIT(-5)(src), l_exc_copy) +EXC( LOAD t0, UNIT(-8)(src), l_exc_copy_rewind16) +EXC( LOAD t1, UNIT(-7)(src), l_exc_copy_rewind16) +EXC( LOAD t2, UNIT(-6)(src), l_exc_copy_rewind16) +EXC( LOAD t3, UNIT(-5)(src), l_exc_copy_rewind16) EXC( STORE t0, UNIT(-8)(dst), s_exc_p8u) EXC( STORE t1, UNIT(-7)(dst), s_exc_p7u) EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u) EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u) -EXC( LOAD t0, UNIT(-4)(src), l_exc_copy) -EXC( LOAD t1, UNIT(-3)(src), l_exc_copy) -EXC( LOAD t2, UNIT(-2)(src), l_exc_copy) -EXC( LOAD t3, UNIT(-1)(src), l_exc_copy) +EXC( LOAD t0, UNIT(-4)(src), l_exc_copy_rewind16) +EXC( LOAD t1, UNIT(-3)(src), l_exc_copy_rewind16) +EXC( LOAD t2, UNIT(-2)(src), l_exc_copy_rewind16) +EXC( LOAD t3, UNIT(-1)(src), l_exc_copy_rewind16) EXC( STORE t0, UNIT(-4)(dst), s_exc_p4u) EXC( STORE t1, UNIT(-3)(dst), s_exc_p3u) EXC( STORE t2, UNIT(-2)(dst), s_exc_p2u) @@ -383,6 +383,10 @@ done: nop END(memcpy) +l_exc_copy_rewind16: + /* Rewind src and dst by 16*NBYTES for l_exc_copy */ + SUB src, src, 16*NBYTES + SUB dst, dst, 16*NBYTES l_exc_copy: /* * Copy bytes from src until faulting load address (or until a diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index 57ed466e00db..2f140d75d01c 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -68,8 +68,8 @@ CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 48e16d98b2cc..b15508447366 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -134,7 +134,7 @@ CONFIG_LIBFC=m CONFIG_SCSI_QLOGIC_1280=y CONFIG_SCSI_PMCRAID=m CONFIG_SCSI_BFA_FC=m -CONFIG_SCSI_DH=m +CONFIG_SCSI_DH=y CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_HP_SW=m CONFIG_SCSI_DH_EMC=m @@ -206,7 +206,6 @@ CONFIG_MLX4_EN=m # CONFIG_MLX4_DEBUG is not set CONFIG_TEHUTI=m CONFIG_BNX2X=m -CONFIG_QLGE=m CONFIG_SFC=m CONFIG_BE2NET=m CONFIG_LIBERTAS_THINFIRM=m diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 004cf52d1b7d..c24b87819ccb 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -39,7 +39,7 @@ CONFIG_HIBERNATION=y CONFIG_PM_STD_PARTITION="/dev/hda3" CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_DEBUG=y -CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=m diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 5afb4840aec7..739ccd0dca64 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -59,8 +59,8 @@ CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig index 98f13879bb8f..47f4ecf125ba 100644 --- a/arch/mips/configs/malta_kvm_defconfig +++ b/arch/mips/configs/malta_kvm_defconfig @@ -60,8 +60,8 @@ CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig index 3b5d5913f548..e79d325aa085 100644 --- a/arch/mips/configs/malta_kvm_guest_defconfig +++ b/arch/mips/configs/malta_kvm_guest_defconfig @@ -59,8 +59,8 @@ CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig index 732215732751..ae87ad86243b 100644 --- a/arch/mips/configs/maltaup_xpa_defconfig +++ b/arch/mips/configs/maltaup_xpa_defconfig @@ -61,8 +61,8 @@ CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig index b3d1d37f85ea..47492fee2952 100644 --- a/arch/mips/configs/nlm_xlp_defconfig +++ b/arch/mips/configs/nlm_xlp_defconfig @@ -111,7 +111,7 @@ CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig index 3d8016d6cf3e..472a818f1eb8 100644 --- a/arch/mips/configs/nlm_xlr_defconfig +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -91,7 +91,7 @@ CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 8c6f508e59de..554d1da97743 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -146,7 +146,25 @@ /* * Find irq with highest priority */ - PTR_LA t1,cpu_mask_nr_tbl + # open coded PTR_LA t1, cpu_mask_nr_tbl +#if (_MIPS_SZPTR == 32) + # open coded la t1, cpu_mask_nr_tbl + lui t1, %hi(cpu_mask_nr_tbl) + addiu t1, %lo(cpu_mask_nr_tbl) + +#endif +#if (_MIPS_SZPTR == 64) + # open coded dla t1, cpu_mask_nr_tbl + .set push + .set noat + lui t1, %highest(cpu_mask_nr_tbl) + lui AT, %hi(cpu_mask_nr_tbl) + daddiu t1, t1, %higher(cpu_mask_nr_tbl) + daddiu AT, AT, %lo(cpu_mask_nr_tbl) + dsll t1, 32 + daddu t1, t1, AT + .set pop +#endif 1: lw t2,(t1) nop and t2,t0 @@ -195,7 +213,25 @@ /* * Find irq with highest priority */ - PTR_LA t1,asic_mask_nr_tbl + # open coded PTR_LA t1,asic_mask_nr_tbl +#if (_MIPS_SZPTR == 32) + # open coded la t1, asic_mask_nr_tbl + lui t1, %hi(asic_mask_nr_tbl) + addiu t1, %lo(asic_mask_nr_tbl) + +#endif +#if (_MIPS_SZPTR == 64) + # open coded dla t1, asic_mask_nr_tbl + .set push + .set noat + lui t1, %highest(asic_mask_nr_tbl) + lui AT, %hi(asic_mask_nr_tbl) + daddiu t1, t1, %higher(asic_mask_nr_tbl) + daddiu AT, AT, %lo(asic_mask_nr_tbl) + dsll t1, 32 + daddu t1, t1, AT + .set pop +#endif 2: lw t2,(t1) nop and t2,t0 diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h index 3ceacde5eb6e..17f89f9670b2 100644 --- a/arch/mips/include/asm/checksum.h +++ b/arch/mips/include/asm/checksum.h @@ -186,7 +186,9 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, " daddu %0, %4 \n" " dsll32 $1, %0, 0 \n" " daddu %0, $1 \n" + " sltu $1, %0, $1 \n" " dsra32 %0, %0, 0 \n" + " addu %0, $1 \n" #endif " .set pop" : "=r" (sum) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 44a6f25e902e..fc537d1b649d 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -191,11 +191,9 @@ struct mips_frame_info { #define J_TARGET(pc,target) \ (((unsigned long)(pc) & 0xf0000000) | ((target) << 2)) -static inline int is_ra_save_ins(union mips_instruction *ip) +static inline int is_ra_save_ins(union mips_instruction *ip, int *poff) { #ifdef CONFIG_CPU_MICROMIPS - union mips_instruction mmi; - /* * swsp ra,offset * swm16 reglist,offset(sp) @@ -205,29 +203,71 @@ static inline int is_ra_save_ins(union mips_instruction *ip) * * microMIPS is way more fun... */ - if (mm_insn_16bit(ip->halfword[0])) { - mmi.word = (ip->halfword[0] << 16); - return (mmi.mm16_r5_format.opcode == mm_swsp16_op && - mmi.mm16_r5_format.rt == 31) || - (mmi.mm16_m_format.opcode == mm_pool16c_op && - mmi.mm16_m_format.func == mm_swm16_op); + if (mm_insn_16bit(ip->halfword[1])) { + switch (ip->mm16_r5_format.opcode) { + case mm_swsp16_op: + if (ip->mm16_r5_format.rt != 31) + return 0; + + *poff = ip->mm16_r5_format.simmediate; + *poff = (*poff << 2) / sizeof(ulong); + return 1; + + case mm_pool16c_op: + switch (ip->mm16_m_format.func) { + case mm_swm16_op: + *poff = ip->mm16_m_format.imm; + *poff += 1 + ip->mm16_m_format.rlist; + *poff = (*poff << 2) / sizeof(ulong); + return 1; + + default: + return 0; + } + + default: + return 0; + } } - else { - mmi.halfword[0] = ip->halfword[1]; - mmi.halfword[1] = ip->halfword[0]; - return (mmi.mm_m_format.opcode == mm_pool32b_op && - mmi.mm_m_format.rd > 9 && - mmi.mm_m_format.base == 29 && - mmi.mm_m_format.func == mm_swm32_func) || - (mmi.i_format.opcode == mm_sw32_op && - mmi.i_format.rs == 29 && - mmi.i_format.rt == 31); + + switch (ip->i_format.opcode) { + case mm_sw32_op: + if (ip->i_format.rs != 29) + return 0; + if (ip->i_format.rt != 31) + return 0; + + *poff = ip->i_format.simmediate / sizeof(ulong); + return 1; + + case mm_pool32b_op: + switch (ip->mm_m_format.func) { + case mm_swm32_func: + if (ip->mm_m_format.rd < 0x10) + return 0; + if (ip->mm_m_format.base != 29) + return 0; + + *poff = ip->mm_m_format.simmediate; + *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32); + *poff /= sizeof(ulong); + return 1; + default: + return 0; + } + + default: + return 0; } #else /* sw / sd $ra, offset($sp) */ - return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && - ip->i_format.rs == 29 && - ip->i_format.rt == 31; + if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && + ip->i_format.rs == 29 && ip->i_format.rt == 31) { + *poff = ip->i_format.simmediate / sizeof(ulong); + return 1; + } + + return 0; #endif } @@ -242,13 +282,16 @@ static inline int is_jump_ins(union mips_instruction *ip) * * microMIPS is kind of more fun... */ - union mips_instruction mmi; - - mmi.word = (ip->halfword[0] << 16); + if (mm_insn_16bit(ip->halfword[1])) { + if ((ip->mm16_r5_format.opcode == mm_pool16c_op && + (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op)) + return 1; + return 0; + } - if ((mmi.mm16_r5_format.opcode == mm_pool16c_op && - (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || - ip->j_format.opcode == mm_jal32_op) + if (ip->j_format.opcode == mm_j32_op) + return 1; + if (ip->j_format.opcode == mm_jal32_op) return 1; if (ip->r_format.opcode != mm_pool32a_op || ip->r_format.func != mm_pool32axf_op) @@ -276,15 +319,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip) * * microMIPS is not more fun... */ - if (mm_insn_16bit(ip->halfword[0])) { - union mips_instruction mmi; - - mmi.word = (ip->halfword[0] << 16); - return (mmi.mm16_r3_format.opcode == mm_pool16d_op && - mmi.mm16_r3_format.simmediate && mm_addiusp_func) || - (mmi.mm16_r5_format.opcode == mm_pool16d_op && - mmi.mm16_r5_format.rt == 29); + if (mm_insn_16bit(ip->halfword[1])) { + return (ip->mm16_r3_format.opcode == mm_pool16d_op && + ip->mm16_r3_format.simmediate && mm_addiusp_func) || + (ip->mm16_r5_format.opcode == mm_pool16d_op && + ip->mm16_r5_format.rt == 29); } + return ip->mm_i_format.opcode == mm_addiu32_op && ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; #else @@ -299,30 +340,36 @@ static inline int is_sp_move_ins(union mips_instruction *ip) static int get_frame_info(struct mips_frame_info *info) { -#ifdef CONFIG_CPU_MICROMIPS - union mips_instruction *ip = (void *) (((char *) info->func) - 1); -#else - union mips_instruction *ip = info->func; -#endif - unsigned max_insns = info->func_size / sizeof(union mips_instruction); - unsigned i; + bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS); + union mips_instruction insn, *ip, *ip_end; + const unsigned int max_insns = 128; + unsigned int i; info->pc_offset = -1; info->frame_size = 0; + ip = (void *)msk_isa16_mode((ulong)info->func); if (!ip) goto err; - if (max_insns == 0) - max_insns = 128U; /* unknown function size */ - max_insns = min(128U, max_insns); + ip_end = (void *)ip + info->func_size; - for (i = 0; i < max_insns; i++, ip++) { + for (i = 0; i < max_insns && ip < ip_end; i++, ip++) { + if (is_mmips && mm_insn_16bit(ip->halfword[0])) { + insn.halfword[0] = 0; + insn.halfword[1] = ip->halfword[0]; + } else if (is_mmips) { + insn.halfword[0] = ip->halfword[1]; + insn.halfword[1] = ip->halfword[0]; + } else { + insn.word = ip->word; + } - if (is_jump_ins(ip)) + if (is_jump_ins(&insn)) break; + if (!info->frame_size) { - if (is_sp_move_ins(ip)) + if (is_sp_move_ins(&insn)) { #ifdef CONFIG_CPU_MICROMIPS if (mm_insn_16bit(ip->halfword[0])) @@ -345,11 +392,9 @@ static int get_frame_info(struct mips_frame_info *info) } continue; } - if (info->pc_offset == -1 && is_ra_save_ins(ip)) { - info->pc_offset = - ip->i_format.simmediate / sizeof(long); + if (info->pc_offset == -1 && + is_ra_save_ins(&insn, &info->pc_offset)) break; - } } if (info->frame_size && info->pc_offset >= 0) /* nested */ return 0; diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 80554e8f6037..3e390a4e3897 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -545,7 +545,7 @@ void __init ltq_soc_init(void) clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI); clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI); clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL); - clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP); + clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); } else if (of_machine_is_compatible("lantiq,ar10")) { @@ -553,7 +553,7 @@ void __init ltq_soc_init(void) ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz()); clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0); clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1); - clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | + clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP | PMU_PPE_TC); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY); @@ -575,11 +575,11 @@ void __init ltq_soc_init(void) clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); - clkdev_add_pmu("1e108000.eth", NULL, 1, 0, + clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | PMU_PPE_QSB | PMU_PPE_TOP); - clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY); + clkdev_add_pmu("1f203000.rcu", "gphy", 0, 0, PMU_GPHY); clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c index dc7c5a5214a9..efaf364fe581 100644 --- a/arch/mips/mm/sc-ip22.c +++ b/arch/mips/mm/sc-ip22.c @@ -31,26 +31,40 @@ static inline void indy_sc_wipe(unsigned long first, unsigned long last) unsigned long tmp; __asm__ __volatile__( - ".set\tpush\t\t\t# indy_sc_wipe\n\t" - ".set\tnoreorder\n\t" - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "mfc0\t%2, $12\n\t" - "li\t$1, 0x80\t\t\t# Go 64 bit\n\t" - "mtc0\t$1, $12\n\t" - - "dli\t$1, 0x9000000080000000\n\t" - "or\t%0, $1\t\t\t# first line to flush\n\t" - "or\t%1, $1\t\t\t# last line to flush\n\t" - ".set\tat\n\t" - - "1:\tsw\t$0, 0(%0)\n\t" - "bne\t%0, %1, 1b\n\t" - " daddu\t%0, 32\n\t" - - "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t" - "nop; nop; nop; nop;\n\t" - ".set\tpop" + " .set push # indy_sc_wipe \n" + " .set noreorder \n" + " .set mips3 \n" + " .set noat \n" + " mfc0 %2, $12 \n" + " li $1, 0x80 # Go 64 bit \n" + " mtc0 $1, $12 \n" + " \n" + " # \n" + " # Open code a dli $1, 0x9000000080000000 \n" + " # \n" + " # Required because binutils 2.25 will happily accept \n" + " # 64 bit instructions in .set mips3 mode but puke on \n" + " # 64 bit constants when generating 32 bit ELF \n" + " # \n" + " lui $1,0x9000 \n" + " dsll $1,$1,0x10 \n" + " ori $1,$1,0x8000 \n" + " dsll $1,$1,0x10 \n" + " \n" + " or %0, $1 # first line to flush \n" + " or %1, $1 # last line to flush \n" + " .set at \n" + " \n" + "1: sw $0, 0(%0) \n" + " bne %0, %1, 1b \n" + " daddu %0, 32 \n" + " \n" + " mtc0 %2, $12 # Back to 32 bit \n" + " nop # pipeline hazard \n" + " nop \n" + " nop \n" + " nop \n" + " .set pop \n" : "=r" (first), "=r" (last), "=&r" (tmp) : "0" (first), "1" (last)); } diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index edbab9b8691f..c474981a6c0d 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -50,7 +50,6 @@ #include <asm/netlogic/xlp-hal/sys.h> #include <asm/netlogic/xlp-hal/cpucontrol.h> -#define CP0_EBASE $15 #define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \ SYS_CPU_NONCOHERENT_MODE * 4 @@ -92,7 +91,7 @@ * registers. On XLPII CPUs, usual cache instructions work. */ .macro xlp_flush_l1_dcache - mfc0 t0, CP0_EBASE, 0 + mfc0 t0, CP0_PRID andi t0, t0, PRID_IMP_MASK slt t1, t0, 0x1200 beqz t1, 15f @@ -171,7 +170,7 @@ FEXPORT(nlm_reset_entry) nop 1: /* Entry point on core wakeup */ - mfc0 t0, CP0_EBASE, 0 /* processor ID */ + mfc0 t0, CP0_PRID /* processor ID */ andi t0, PRID_IMP_MASK li t1, 0x1500 /* XLP 9xx */ beq t0, t1, 2f /* does not need to set coherent */ @@ -182,8 +181,8 @@ FEXPORT(nlm_reset_entry) nop /* set bit in SYS coherent register for the core */ - mfc0 t0, CP0_EBASE, 1 - mfc0 t1, CP0_EBASE, 1 + mfc0 t0, CP0_EBASE + mfc0 t1, CP0_EBASE srl t1, 5 andi t1, 0x3 /* t1 <- node */ li t2, 0x40000 @@ -232,7 +231,7 @@ EXPORT(nlm_boot_siblings) * NOTE: All GPR contents are lost after the mtcr above! */ - mfc0 v0, CP0_EBASE, 1 + mfc0 v0, CP0_EBASE andi v0, 0x3ff /* v0 <- node/core */ /* diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index 805355b0bd05..f0cc4c9de2bb 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -48,8 +48,6 @@ #include <asm/netlogic/xlp-hal/sys.h> #include <asm/netlogic/xlp-hal/cpucontrol.h> -#define CP0_EBASE $15 - .set noreorder .set noat .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ @@ -86,7 +84,7 @@ NESTED(nlm_boot_secondary_cpus, 16, sp) PTR_L gp, 0(t1) /* a0 has the processor id */ - mfc0 a0, CP0_EBASE, 1 + mfc0 a0, CP0_EBASE andi a0, 0x3ff /* a0 <- node/core */ PTR_LA t0, nlm_early_init_secondary jalr t0 diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c index 39a9142f71be..7ecb4af79b7b 100644 --- a/arch/mips/ralink/prom.c +++ b/arch/mips/ralink/prom.c @@ -30,8 +30,10 @@ const char *get_system_type(void) return soc_info.sys_type; } -static __init void prom_init_cmdline(int argc, char **argv) +static __init void prom_init_cmdline(void) { + int argc; + char **argv; int i; pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n", @@ -60,14 +62,11 @@ static __init void prom_init_cmdline(int argc, char **argv) void __init prom_init(void) { - int argc; - char **argv; - prom_soc_init(&soc_info); pr_info("SoC Type: %s\n", get_system_type()); - prom_init_cmdline(argc, argv); + prom_init_cmdline(); } void __init prom_free_prom_memory(void) diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 844f5cd55c8f..15506a1ff22a 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -40,16 +40,6 @@ static struct rt2880_pmx_group rt2880_pinmux_data_act[] = { { 0 } }; -static void rt288x_wdt_reset(void) -{ - u32 t; - - /* enable WDT reset output on pin SRAM_CS_N */ - t = rt_sysc_r32(SYSC_REG_CLKCFG); - t |= CLKCFG_SRAM_CS_N_WDT; - rt_sysc_w32(t, SYSC_REG_CLKCFG); -} - void __init ralink_clk_init(void) { unsigned long cpu_rate, wmac_rate = 40000000; diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index 9e4572592065..15b32cd01906 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -89,17 +89,6 @@ static struct rt2880_pmx_group rt5350_pinmux_data[] = { { 0 } }; -static void rt305x_wdt_reset(void) -{ - u32 t; - - /* enable WDT reset output on pin SRAM_CS_N */ - t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); - t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT << - RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT; - rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG); -} - static unsigned long rt5350_get_mem_size(void) { void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index 582995aaaf4e..f42834c7f007 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -63,16 +63,6 @@ static struct rt2880_pmx_group rt3883_pinmux_data[] = { { 0 } }; -static void rt3883_wdt_reset(void) -{ - u32 t; - - /* enable WDT reset output on GPIO 2 */ - t = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1); - t |= RT3883_SYSCFG1_GPIO2_AS_WDT_OUT; - rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1); -} - void __init ralink_clk_init(void) { unsigned long cpu_rate, sys_rate; diff --git a/arch/mips/sgi-ip22/Platform b/arch/mips/sgi-ip22/Platform index b7a4b7e04c38..e8f6b3a42a48 100644 --- a/arch/mips/sgi-ip22/Platform +++ b/arch/mips/sgi-ip22/Platform @@ -25,7 +25,7 @@ endif # Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys # ifdef CONFIG_SGI_IP28 - ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n) + ifeq ($(call cc-option-yn,-march=r10000 -mr10k-cache-barrier=store), n) $(error gcc doesn't support needed option -mr10k-cache-barrier=store) endif endif diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 05e804cdecaa..fdf48785d3e9 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -227,8 +227,10 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) rcu_read_lock(); bp = __this_cpu_read(bp_per_reg); - if (!bp) + if (!bp) { + rc = NOTIFY_DONE; goto out; + } info = counter_arch_bp(bp); /* diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index dc885b30f7a6..4014881e9843 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -1806,8 +1806,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) goto instr_done; case LARX: - if (regs->msr & MSR_LE) - return 0; if (op.ea & (size - 1)) break; /* can't handle misaligned */ err = -EFAULT; @@ -1829,8 +1827,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) goto ldst_done; case STCX: - if (regs->msr & MSR_LE) - return 0; if (op.ea & (size - 1)) break; /* can't handle misaligned */ err = -EFAULT; @@ -1854,8 +1850,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) goto ldst_done; case LOAD: - if (regs->msr & MSR_LE) - return 0; err = read_mem(®s->gpr[op.reg], op.ea, size, regs); if (!err) { if (op.type & SIGNEXT) @@ -1867,8 +1861,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) #ifdef CONFIG_PPC_FPU case LOAD_FP: - if (regs->msr & MSR_LE) - return 0; if (size == 4) err = do_fp_load(op.reg, do_lfs, op.ea, size, regs); else @@ -1877,15 +1869,11 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) #endif #ifdef CONFIG_ALTIVEC case LOAD_VMX: - if (regs->msr & MSR_LE) - return 0; err = do_vec_load(op.reg, do_lvx, op.ea & ~0xfUL, regs); goto ldst_done; #endif #ifdef CONFIG_VSX case LOAD_VSX: - if (regs->msr & MSR_LE) - return 0; err = do_vsx_load(op.reg, do_lxvd2x, op.ea, regs); goto ldst_done; #endif @@ -1908,8 +1896,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) goto instr_done; case STORE: - if (regs->msr & MSR_LE) - return 0; if ((op.type & UPDATE) && size == sizeof(long) && op.reg == 1 && op.update_reg == 1 && !(regs->msr & MSR_PR) && @@ -1922,8 +1908,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) #ifdef CONFIG_PPC_FPU case STORE_FP: - if (regs->msr & MSR_LE) - return 0; if (size == 4) err = do_fp_store(op.reg, do_stfs, op.ea, size, regs); else @@ -1932,15 +1916,11 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) #endif #ifdef CONFIG_ALTIVEC case STORE_VMX: - if (regs->msr & MSR_LE) - return 0; err = do_vec_store(op.reg, do_stvx, op.ea & ~0xfUL, regs); goto ldst_done; #endif #ifdef CONFIG_VSX case STORE_VSX: - if (regs->msr & MSR_LE) - return 0; err = do_vsx_store(op.reg, do_stxvd2x, op.ea, regs); goto ldst_done; #endif diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index c1ea67db8404..c61ed7890cef 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -74,7 +74,8 @@ extern void execve_tail(void); * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. */ -#define TASK_SIZE_OF(tsk) ((tsk)->mm->context.asce_limit) +#define TASK_SIZE_OF(tsk) ((tsk)->mm ? \ + (tsk)->mm->context.asce_limit : TASK_MAX_SIZE) #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ (1UL << 30) : (1UL << 41)) #define TASK_SIZE TASK_SIZE_OF(current) diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 171e09bb8ea2..f7c3a61040bd 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -23,6 +23,8 @@ #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y)))) +#define LINUX_NOTE_NAME "LINUX" + static struct memblock_region oldmem_region; static struct memblock_type oldmem_type = { @@ -312,7 +314,7 @@ static void *nt_fpregset(void *ptr, struct save_area *sa) static void *nt_s390_timer(void *ptr, struct save_area *sa) { return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer), - KEXEC_CORE_NOTE_NAME); + LINUX_NOTE_NAME); } /* @@ -321,7 +323,7 @@ static void *nt_s390_timer(void *ptr, struct save_area *sa) static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa) { return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp, - sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME); + sizeof(sa->clk_cmp), LINUX_NOTE_NAME); } /* @@ -330,7 +332,7 @@ static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa) static void *nt_s390_tod_preg(void *ptr, struct save_area *sa) { return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg, - sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME); + sizeof(sa->tod_reg), LINUX_NOTE_NAME); } /* @@ -339,7 +341,7 @@ static void *nt_s390_tod_preg(void *ptr, struct save_area *sa) static void *nt_s390_ctrs(void *ptr, struct save_area *sa) { return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs, - sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME); + sizeof(sa->ctrl_regs), LINUX_NOTE_NAME); } /* @@ -348,7 +350,7 @@ static void *nt_s390_ctrs(void *ptr, struct save_area *sa) static void *nt_s390_prefix(void *ptr, struct save_area *sa) { return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg, - sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME); + sizeof(sa->pref_reg), LINUX_NOTE_NAME); } /* @@ -357,7 +359,7 @@ static void *nt_s390_prefix(void *ptr, struct save_area *sa) static void *nt_s390_vx_high(void *ptr, __vector128 *vx_regs) { return nt_init(ptr, NT_S390_VXRS_HIGH, &vx_regs[16], - 16 * sizeof(__vector128), KEXEC_CORE_NOTE_NAME); + 16 * sizeof(__vector128), LINUX_NOTE_NAME); } /* @@ -370,12 +372,12 @@ static void *nt_s390_vx_low(void *ptr, __vector128 *vx_regs) int i; note = (Elf64_Nhdr *)ptr; - note->n_namesz = strlen(KEXEC_CORE_NOTE_NAME) + 1; + note->n_namesz = strlen(LINUX_NOTE_NAME) + 1; note->n_descsz = 16 * 8; note->n_type = NT_S390_VXRS_LOW; len = sizeof(Elf64_Nhdr); - memcpy(ptr + len, KEXEC_CORE_NOTE_NAME, note->n_namesz); + memcpy(ptr + len, LINUX_NOTE_NAME, note->n_namesz); len = roundup(len + note->n_namesz, 4); ptr += len; diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 1f581eb61bc2..d097d71685df 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -805,10 +805,10 @@ static void __init setup_randomness(void) { struct sysinfo_3_2_2 *vmms; - vmms = (struct sysinfo_3_2_2 *) alloc_page(GFP_KERNEL); - if (vmms && stsi(vmms, 3, 2, 2) == 0 && vmms->count) - add_device_randomness(&vmms, vmms->count); - free_page((unsigned long) vmms); + vmms = (struct sysinfo_3_2_2 *) memblock_alloc(PAGE_SIZE, PAGE_SIZE); + if (stsi(vmms, 3, 2, 2) == 0 && vmms->count) + add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count); + memblock_free((unsigned long) vmms, PAGE_SIZE); } /* diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 575dc123bda2..23e3f5d77a24 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -295,6 +295,9 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot; int is_dirty = 0; + if (kvm_is_ucontrol(kvm)) + return -EINVAL; + mutex_lock(&kvm->slots_lock); r = -EINVAL; diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 8345ae1f117d..05ae254f84cf 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -1237,11 +1237,28 @@ EXPORT_SYMBOL_GPL(s390_reset_cmma); */ bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) { + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; pte_t *pte; spinlock_t *ptl; bool dirty = false; - pte = get_locked_pte(gmap->mm, address, &ptl); + pgd = pgd_offset(gmap->mm, address); + pud = pud_alloc(gmap->mm, pgd, address); + if (!pud) + return false; + pmd = pmd_alloc(gmap->mm, pud, address); + if (!pmd) + return false; + /* We can't run guests backed by huge pages, but userspace can + * still set them up and then try to migrate them without any + * migration support. + */ + if (pmd_large(*pmd)) + return true; + + pte = pte_alloc_map_lock(gmap->mm, pmd, address, &ptl); if (unlikely(!pte)) return false; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index bb620df05d0d..3a7ae80dc49d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3499,7 +3499,7 @@ static void fix_rmode_seg(int seg, struct kvm_segment *save) } vmcs_write16(sf->selector, var.selector); - vmcs_write32(sf->base, var.base); + vmcs_writel(sf->base, var.base); vmcs_write32(sf->limit, var.limit); vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(&var)); } @@ -4867,6 +4867,12 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) if (vmx_xsaves_supported()) vmcs_write64(XSS_EXIT_BITMAP, VMX_XSS_EXIT_BITMAP); + if (enable_pml) { + ASSERT(vmx->pml_pg); + vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); + vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); + } + return 0; } @@ -7839,22 +7845,6 @@ static void vmx_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2) *info2 = vmcs_read32(VM_EXIT_INTR_INFO); } -static int vmx_create_pml_buffer(struct vcpu_vmx *vmx) -{ - struct page *pml_pg; - - pml_pg = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!pml_pg) - return -ENOMEM; - - vmx->pml_pg = pml_pg; - - vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); - vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); - - return 0; -} - static void vmx_destroy_pml_buffer(struct vcpu_vmx *vmx) { if (vmx->pml_pg) { @@ -7915,7 +7905,7 @@ static void kvm_flush_pml_buffers(struct kvm *kvm) static void vmx_dump_sel(char *name, uint32_t sel) { pr_err("%s sel=0x%04x, attr=0x%05x, limit=0x%08x, base=0x%016lx\n", - name, vmcs_read32(sel), + name, vmcs_read16(sel), vmcs_read32(sel + GUEST_ES_AR_BYTES - GUEST_ES_SELECTOR), vmcs_read32(sel + GUEST_ES_LIMIT - GUEST_ES_SELECTOR), vmcs_readl(sel + GUEST_ES_BASE - GUEST_ES_SELECTOR)); @@ -8789,14 +8779,26 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) if (err) goto free_vcpu; + err = -ENOMEM; + + /* + * If PML is turned on, failure on enabling PML just results in failure + * of creating the vcpu, therefore we can simplify PML logic (by + * avoiding dealing with cases, such as enabling PML partially on vcpus + * for the guest, etc. + */ + if (enable_pml) { + vmx->pml_pg = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!vmx->pml_pg) + goto uninit_vcpu; + } + vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); BUILD_BUG_ON(ARRAY_SIZE(vmx_msr_index) * sizeof(vmx->guest_msrs[0]) > PAGE_SIZE); - err = -ENOMEM; - if (!vmx->guest_msrs) { - goto uninit_vcpu; - } + if (!vmx->guest_msrs) + goto free_pml; vmx->loaded_vmcs = &vmx->vmcs01; vmx->loaded_vmcs->vmcs = alloc_vmcs(); @@ -8840,18 +8842,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) vmx->nested.current_vmptr = -1ull; vmx->nested.current_vmcs12 = NULL; - /* - * If PML is turned on, failure on enabling PML just results in failure - * of creating the vcpu, therefore we can simplify PML logic (by - * avoiding dealing with cases, such as enabling PML partially on vcpus - * for the guest, etc. - */ - if (enable_pml) { - err = vmx_create_pml_buffer(vmx); - if (err) - goto free_vmcs; - } - return &vmx->vcpu; free_vmcs: @@ -8859,6 +8849,8 @@ free_vmcs: free_loaded_vmcs(vmx->loaded_vmcs); free_msrs: kfree(vmx->guest_msrs); +free_pml: + vmx_destroy_pml_buffer(vmx); uninit_vcpu: kvm_vcpu_uninit(&vmx->vcpu); free_vcpu: diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c index 1693107a518e..0d17c0aafeb1 100644 --- a/arch/x86/platform/goldfish/goldfish.c +++ b/arch/x86/platform/goldfish/goldfish.c @@ -42,10 +42,22 @@ static struct resource goldfish_pdev_bus_resources[] = { } }; +static bool goldfish_enable __initdata; + +static int __init goldfish_setup(char *str) +{ + goldfish_enable = true; + return 0; +} +__setup("goldfish", goldfish_setup); + static int __init goldfish_init(void) { + if (!goldfish_enable) + return -ENODEV; + platform_device_register_simple("goldfish_pdev_bus", -1, - goldfish_pdev_bus_resources, 2); + goldfish_pdev_bus_resources, 2); return 0; } device_initcall(goldfish_init); diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 9735691f37f1..49ccbd9022f6 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -133,6 +133,8 @@ static int __init parse_tag_initrd(const bp_tag_t* tag) __tagtable(BP_TAG_INITRD, parse_tag_initrd); +#endif /* CONFIG_BLK_DEV_INITRD */ + #ifdef CONFIG_OF static int __init parse_tag_fdt(const bp_tag_t *tag) @@ -145,8 +147,6 @@ __tagtable(BP_TAG_FDT, parse_tag_fdt); #endif /* CONFIG_OF */ -#endif /* CONFIG_BLK_DEV_INITRD */ - static int __init parse_tag_cmdline(const bp_tag_t* tag) { strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE); diff --git a/block/blk-mq.c b/block/blk-mq.c index 40a0364fe183..8bd548378822 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1259,12 +1259,9 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) blk_queue_split(q, &bio, q->bio_split); - if (!is_flush_fua && !blk_queue_nomerges(q)) { - if (blk_attempt_plug_merge(q, bio, &request_count, - &same_queue_rq)) - return BLK_QC_T_NONE; - } else - request_count = blk_plug_queued_count(q); + if (!is_flush_fua && !blk_queue_nomerges(q) && + blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq)) + return BLK_QC_T_NONE; rq = blk_mq_map_request(q, bio, &data); if (unlikely(!rq)) @@ -1355,9 +1352,11 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio) blk_queue_split(q, &bio, q->bio_split); - if (!is_flush_fua && !blk_queue_nomerges(q) && - blk_attempt_plug_merge(q, bio, &request_count, NULL)) - return BLK_QC_T_NONE; + if (!is_flush_fua && !blk_queue_nomerges(q)) { + if (blk_attempt_plug_merge(q, bio, &request_count, NULL)) + return BLK_QC_T_NONE; + } else + request_count = blk_plug_queued_count(q); rq = blk_mq_map_request(q, bio, &data); if (unlikely(!rq)) diff --git a/crypto/Makefile b/crypto/Makefile index 82fbff180ad3..03e66097eb0c 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_CRYPTO_SHA1) += sha1_generic.o obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o obj-$(CONFIG_CRYPTO_SHA512) += sha512_generic.o obj-$(CONFIG_CRYPTO_WP512) += wp512.o +CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149 obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o obj-$(CONFIG_CRYPTO_ECB) += ecb.o @@ -85,6 +86,7 @@ obj-$(CONFIG_CRYPTO_BLOWFISH_COMMON) += blowfish_common.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o +CFLAGS_serpent_generic.o := $(call cc-option,-fsched-pressure) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o diff --git a/crypto/testmgr.h b/crypto/testmgr.h index da0a8fd765f4..0e02c60a57b6 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -21778,7 +21778,7 @@ static struct aead_testvec aes_ccm_enc_tv_template[] = { "\x09\x75\x9a\x9b\x3c\x9b\x27\x39", .klen = 32, .iv = "\x03\xf9\xd9\x4e\x63\xb5\x3d\x9d" - "\x43\xf6\x1e\x50", + "\x43\xf6\x1e\x50\0\0\0\0", .assoc = "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b" "\x13\x02\x01\x0c\x83\x4c\x96\x35" "\x8e\xd6\x39\xcf\x7d\x14\x9b\x94" diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index c097f477c74c..14c2a07c9f3f 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -965,7 +965,7 @@ static size_t sizeof_nfit_set_info(int num_mappings) + num_mappings * sizeof(struct nfit_set_info_map); } -static int cmp_map(const void *m0, const void *m1) +static int cmp_map_compat(const void *m0, const void *m1) { const struct nfit_set_info_map *map0 = m0; const struct nfit_set_info_map *map1 = m1; @@ -974,6 +974,14 @@ static int cmp_map(const void *m0, const void *m1) sizeof(u64)); } +static int cmp_map(const void *m0, const void *m1) +{ + const struct nfit_set_info_map *map0 = m0; + const struct nfit_set_info_map *map1 = m1; + + return map0->region_offset - map1->region_offset; +} + /* Retrieve the nth entry referencing this spa */ static struct acpi_nfit_memory_map *memdev_from_spa( struct acpi_nfit_desc *acpi_desc, u16 range_index, int n) @@ -1029,6 +1037,12 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), cmp_map, NULL); nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); + + /* support namespaces created with the wrong sort order */ + sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), + cmp_map_compat, NULL); + nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); + ndr_desc->nd_set = nd_set; devm_kfree(dev, info); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 59d8d0d14824..327f9e374b44 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -640,8 +640,11 @@ static int bcma_device_probe(struct device *dev) drv); int err = 0; + get_device(dev); if (adrv->probe) err = adrv->probe(core); + if (err) + put_device(dev); return err; } @@ -654,6 +657,7 @@ static int bcma_device_remove(struct device *dev) if (adrv->remove) adrv->remove(core); + put_device(dev); return 0; } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ab0b2dd3f629..cec36d5c24f5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1108,9 +1108,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; + /* I/O need to be drained during transfer transition */ + blk_mq_freeze_queue(lo->lo_queue); + err = loop_release_xfer(lo); if (err) - return err; + goto exit; if (info->lo_encrypt_type) { unsigned int type = info->lo_encrypt_type; @@ -1125,12 +1128,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) err = loop_init_xfer(lo, xfer, info); if (err) - return err; + goto exit; if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) - if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) - return -EFBIG; + if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) { + err = -EFBIG; + goto exit; + } loop_config_discard(lo); @@ -1148,13 +1153,6 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) (info->lo_flags & LO_FLAGS_AUTOCLEAR)) lo->lo_flags ^= LO_FLAGS_AUTOCLEAR; - if ((info->lo_flags & LO_FLAGS_PARTSCAN) && - !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { - lo->lo_flags |= LO_FLAGS_PARTSCAN; - lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; - loop_reread_partitions(lo, lo->lo_device); - } - lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_init[0] = info->lo_init[0]; lo->lo_init[1] = info->lo_init[1]; @@ -1167,7 +1165,17 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) /* update dio if lo_offset or transfer is changed */ __loop_update_dio(lo, lo->use_dio); - return 0; + exit: + blk_mq_unfreeze_queue(lo->lo_queue); + + if (!err && (info->lo_flags & LO_FLAGS_PARTSCAN) && + !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { + lo->lo_flags |= LO_FLAGS_PARTSCAN; + lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; + loop_reread_partitions(lo, lo->lo_device); + } + + return err; } static int diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 0beaa52df66b..5df8e1234505 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -94,6 +94,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x300f) }, { USB_DEVICE(0x04CA, 0x3010) }, { USB_DEVICE(0x04CA, 0x3014) }, + { USB_DEVICE(0x04CA, 0x3018) }, { USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x021c) }, { USB_DEVICE(0x0930, 0x0220) }, @@ -160,6 +161,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c306b483de60..cd6b141b9825 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -208,6 +208,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 3f9f7a999fdf..b04008c8fec3 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -855,7 +855,7 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) __func__, fwd_info->peripheral, fwd_info->type); return 0; } - + mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 1; diagfwd_buffers_init(fwd_info); diagfwd_write_buffers_init(fwd_info); @@ -873,7 +873,7 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); } - + mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); return 0; } @@ -883,6 +883,7 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) if (!fwd_info) return -EIO; + mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 0; if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close) fwd_info->c_ops->close(fwd_info); @@ -898,7 +899,7 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered closed\n", fwd_info->peripheral, fwd_info->type); - + mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); return 0; } diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c index 96fb986402eb..296b23960815 100644 --- a/drivers/char/hw_random/msm-rng.c +++ b/drivers/char/hw_random/msm-rng.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013,2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -156,6 +156,7 @@ static int msm_rng_probe(struct platform_device *pdev) rng->hwrng.init = msm_rng_init, rng->hwrng.cleanup = msm_rng_cleanup, rng->hwrng.read = msm_rng_read, + rng->hwrng.quality = 700; ret = devm_hwrng_register(&pdev->dev, &rng->hwrng); if (ret) { diff --git a/drivers/clk/msm/clock-alpha-pll.c b/drivers/clk/msm/clock-alpha-pll.c index b9a1167a790d..834315aa4993 100644 --- a/drivers/clk/msm/clock-alpha-pll.c +++ b/drivers/clk/msm/clock-alpha-pll.c @@ -612,13 +612,17 @@ static int alpha_pll_set_rate(struct clk *c, unsigned long rate) return -EINVAL; } + if (pll->no_irq_dis) + spin_lock(&c->lock); + else + spin_lock_irqsave(&c->lock, flags); + /* * For PLLs that do not support dynamic programming (dynamic_update * is not set), ensure PLL is off before changing rate. For * optimization reasons, assume no downstream clock is actively * using it. */ - spin_lock_irqsave(&c->lock, flags); if (c->count && !pll->dynamic_update) c->ops->disable(c); @@ -644,7 +648,10 @@ static int alpha_pll_set_rate(struct clk *c, unsigned long rate) if (c->count && !pll->dynamic_update) c->ops->enable(c); - spin_unlock_irqrestore(&c->lock, flags); + if (pll->no_irq_dis) + spin_unlock(&c->lock); + else + spin_unlock_irqrestore(&c->lock, flags); return 0; } diff --git a/drivers/clk/msm/clock-cpu-8996.c b/drivers/clk/msm/clock-cpu-8996.c index 7e03a599fccc..bcda6f31d6f5 100644 --- a/drivers/clk/msm/clock-cpu-8996.c +++ b/drivers/clk/msm/clock-cpu-8996.c @@ -238,6 +238,7 @@ static struct alpha_pll_clk perfcl_alt_pll = { .post_div_config = 0x100, /* Div-2 */ .config_ctl_val = 0x4001051B, .offline_bit_workaround = true, + .no_irq_dis = true, .c = { .always_on = true, .parent = &alpha_xo_ao.c, @@ -300,6 +301,7 @@ static struct alpha_pll_clk pwrcl_alt_pll = { .post_div_config = 0x100, /* Div-2 */ .config_ctl_val = 0x4001051B, .offline_bit_workaround = true, + .no_irq_dis = true, .c = { .always_on = true, .dbg_name = "pwrcl_alt_pll", diff --git a/drivers/clk/msm/clock-gcc-8996.c b/drivers/clk/msm/clock-gcc-8996.c index a9e0b53c3b22..e93e9c494023 100644 --- a/drivers/clk/msm/clock-gcc-8996.c +++ b/drivers/clk/msm/clock-gcc-8996.c @@ -105,6 +105,8 @@ DEFINE_CLK_DUMMY(gcc_ce1_axi_m_clk, 0); DEFINE_CLK_DUMMY(measure_only_bimc_hmss_axi_clk, 0); DEFINE_CLK_RPM_SMD_XO_BUFFER(ln_bb_clk, ln_bb_a_clk, LN_BB_CLK_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(ln_bb_clk_pin, ln_bb_a_clk_pin, + LN_BB_CLK_PIN_ID); static DEFINE_CLK_VOTER(mcd_ce1_clk, &ce1_clk.c, 85710000); static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX); @@ -1340,9 +1342,11 @@ static struct rcg_clk pdm2_clk_src = { }, }; -/* Frequency table might change later */ static struct clk_freq_tbl ftbl_qspi_ser_clk_src[] = { - F( 192000000, gpll4_out_main, 2, 0, 0), + F( 75000000, gpll0_out_main, 8, 0, 0), + F( 150000000, gpll0_out_main, 4, 0, 0), + F( 256000000, gpll4_out_main, 1.5, 0, 0), + F( 300000000, gpll0_out_main, 2, 0, 0), F_END }; @@ -3387,6 +3391,8 @@ static struct clk_lookup msm_clocks_rpm_8996[] = { CLK_LIST(ipa_clk), CLK_LIST(ln_bb_clk), CLK_LIST(ln_bb_a_clk), + CLK_LIST(ln_bb_clk_pin), + CLK_LIST(ln_bb_a_clk_pin), CLK_LIST(mcd_ce1_clk), CLK_LIST(pnoc_keepalive_a_clk), CLK_LIST(pnoc_msmbus_clk), diff --git a/drivers/devfreq/governor_spdm_bw_hyp.c b/drivers/devfreq/governor_spdm_bw_hyp.c index cd068a3097ce..f18b72af5fc4 100644 --- a/drivers/devfreq/governor_spdm_bw_hyp.c +++ b/drivers/devfreq/governor_spdm_bw_hyp.c @@ -1,5 +1,5 @@ /* -*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 @@ -84,6 +84,10 @@ static irqreturn_t threaded_isr(int irq, void *dev_id) (int)desc.arg[0], ext_status); mutex_lock(&devfreqs_lock); list_for_each_entry(data, &devfreqs, list) { + if (data == NULL || data->devfreq == NULL) { + pr_err("Spurious interrupts\n"); + break; + } if (data->spdm_client == desc.ret[0]) { devfreq_monitor_suspend(data->devfreq); mutex_lock(&data->devfreq->lock); diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index dd184b50e5b4..284627806b88 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -272,7 +272,7 @@ static void ipu_irq_handler(struct irq_desc *desc) u32 status; int i, line; - for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) { + for (i = 0; i < IPU_IRQ_NR_BANKS; i++) { struct ipu_irq_bank *bank = irq_bank + i; raw_spin_lock(&bank_lock); diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 7a5e89636b64..1e5f35d8422d 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -937,6 +937,10 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, mdm->dual_interface = of_property_read_bool(node, "qcom,mdm-dual-link"); esoc->link_name = MDM9x55_PCIE; + ret = of_property_read_string(node, "qcom,mdm-link-info", + &esoc->link_info); + if (ret) + dev_info(mdm->dev, "esoc link info missing\n"); esoc->clink_ops = clink_ops; esoc->parent = mdm->dev; esoc->owner = THIS_MODULE; diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h index efa2a1d5e5a6..755fb24bd60a 100644 --- a/drivers/esoc/esoc.h +++ b/drivers/esoc/esoc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,7 @@ struct esoc_eng { * struct esoc_clink: Representation of external esoc device * @name: Name of the external esoc. * @link_name: name of the physical link. + * @link_info: additional info about the physical link. * @parent: parent device. * @dev: device for userspace interface. * @id: id of the external device. @@ -62,6 +63,7 @@ struct esoc_eng { struct esoc_clink { const char *name; const char *link_name; + const char *link_info; struct device *parent; struct device dev; unsigned int id; diff --git a/drivers/esoc/esoc_bus.c b/drivers/esoc/esoc_bus.c index c4397f6fd196..f925607511ba 100644 --- a/drivers/esoc/esoc_bus.c +++ b/drivers/esoc/esoc_bus.c @@ -32,10 +32,19 @@ esoc_link_show(struct device *dev, struct device_attribute *attr, to_esoc_clink(dev)->link_name); } +static ssize_t +esoc_link_info_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, ESOC_LINK_LEN, "%s", + to_esoc_clink(dev)->link_info); +} + static struct device_attribute esoc_clink_attrs[] = { __ATTR_RO(esoc_name), __ATTR_RO(esoc_link), + __ATTR_RO(esoc_link_info), __ATTR_NULL, }; diff --git a/drivers/esoc/esoc_client.c b/drivers/esoc/esoc_client.c index e9932ea3e964..0fe7a83cc3c2 100644 --- a/drivers/esoc/esoc_client.c +++ b/drivers/esoc/esoc_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,7 +43,7 @@ struct esoc_desc *devm_register_esoc_client(struct device *dev, struct device_node *np = dev->of_node; struct esoc_clink *esoc_clink; struct esoc_desc *desc; - char *esoc_name, *esoc_link; + char *esoc_name, *esoc_link, *esoc_link_info; for (index = 0;; index++) { esoc_prop = kasprintf(GFP_KERNEL, "esoc-%d", index); @@ -85,16 +85,26 @@ struct esoc_desc *devm_register_esoc_client(struct device *dev, kfree(esoc_name); return ERR_PTR(-ENOMEM); } + esoc_link_info = kasprintf(GFP_KERNEL, "%s", + esoc_clink->link_info); + if (IS_ERR_OR_NULL(esoc_link_info)) { + dev_err(dev, "unable to alloc link info name\n"); + kfree(esoc_name); + kfree(esoc_link); + return ERR_PTR(-ENOMEM); + } desc = devres_alloc(devm_esoc_desc_release, sizeof(*desc), GFP_KERNEL); if (IS_ERR_OR_NULL(desc)) { kfree(esoc_name); kfree(esoc_link); + kfree(esoc_link_info); dev_err(dev, "unable to allocate esoc descriptor\n"); return ERR_PTR(-ENOMEM); } desc->name = esoc_name; desc->link = esoc_link; + desc->link_info = esoc_link_info; desc->priv = esoc_clink; devres_add(dev, desc); return desc; diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index dc4214f7a302..fa90330db93b 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -57,6 +57,10 @@ * TZ 3.X version info */ #define QSEE_VERSION_TZ_3_X 0x800000 +/* + * TZ 4.X version info + */ +#define QSEE_VERSION_TZ_4_X 0x1000000 #define TZBSP_AES_256_ENCRYPTED_KEY_SIZE 256 #define TZBSP_NONCE_LEN 12 @@ -130,6 +134,18 @@ struct tzdbg_int_t { uint64_t int_count[TZBSP_MAX_CPU_COUNT]; /* # of times seen per CPU */ }; +/* + * Interrupt Info Table used in tz version >=4.X + */ +struct tzdbg_int_t_tz40 { + uint16_t int_info; + uint8_t avail; + uint8_t spare; + uint32_t int_num; + uint8_t int_desc[TZBSP_MAX_INT_DESC]; + uint32_t int_count[TZBSP_MAX_CPU_COUNT]; /* uint32_t in TZ ver >= 4.x*/ +}; + /* warm boot reason for cores */ struct tzbsp_diag_wakeup_info_t { /* Wake source info : APCS_GICC_HPPIR */ @@ -291,6 +307,7 @@ struct tzdbg { struct tzdbg_stat stat[TZDBG_STATS_MAX]; uint32_t hyp_debug_rw_buf_size; bool is_hyplog_enabled; + uint32_t tz_version; }; static struct tzdbg tzdbg = { @@ -364,31 +381,9 @@ static int _disp_tz_boot_stats(void) int len = 0; struct tzdbg_boot_info_t *ptr = NULL; struct tzdbg_boot_info64_t *ptr_64 = NULL; - int ret = 0; - uint32_t smc_id = 0; - uint32_t feature = 10; - struct qseecom_command_scm_resp resp = {}; - struct scm_desc desc = {0}; - if (!is_scm_armv8()) { - ret = scm_call(SCM_SVC_INFO, SCM_SVC_UTIL, &feature, - sizeof(feature), &resp, sizeof(resp)); - } else { - smc_id = TZ_INFO_GET_FEATURE_VERSION_ID; - desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID; - desc.args[0] = feature; - ret = scm_call2(smc_id, &desc); - resp.result = desc.ret[0]; - } - - if (ret) { - pr_err("%s: scm_call to register log buffer failed\n", - __func__); - return 0; - } - pr_info("qsee_version = 0x%x\n", resp.result); - - if (resp.result >= QSEE_VERSION_TZ_3_X) { + pr_info("qsee_version = 0x%x\n", tzdbg.tz_version); + if (tzdbg.tz_version >= QSEE_VERSION_TZ_3_X) { ptr_64 = (struct tzdbg_boot_info64_t *)((unsigned char *) tzdbg.diag_buf + tzdbg.diag_buf->boot_info_off); } else { @@ -397,7 +392,7 @@ static int _disp_tz_boot_stats(void) } for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) { - if (resp.result >= QSEE_VERSION_TZ_3_X) { + if (tzdbg.tz_version >= QSEE_VERSION_TZ_3_X) { len += snprintf(tzdbg.disp_buf + len, (debug_rw_buf_size - 1) - len, " CPU #: %d\n" @@ -487,6 +482,7 @@ static int _disp_tz_interrupt_stats(void) int *num_int; unsigned char *ptr; struct tzdbg_int_t *tzdbg_ptr; + struct tzdbg_int_t_tz40 *tzdbg_ptr_tz40; num_int = (uint32_t *)((unsigned char *)tzdbg.diag_buf + (tzdbg.diag_buf->int_info_off - sizeof(uint32_t))); @@ -495,9 +491,12 @@ static int _disp_tz_interrupt_stats(void) int_info_size = ((tzdbg.diag_buf->ring_off - tzdbg.diag_buf->int_info_off)/(*num_int)); - for (i = 0; i < (*num_int); i++) { - tzdbg_ptr = (struct tzdbg_int_t *)ptr; - len += snprintf(tzdbg.disp_buf + len, + pr_info("qsee_version = 0x%x\n", tzdbg.tz_version); + + if (tzdbg.tz_version < QSEE_VERSION_TZ_4_X) { + for (i = 0; i < (*num_int); i++) { + tzdbg_ptr = (struct tzdbg_int_t *)ptr; + len += snprintf(tzdbg.disp_buf + len, (debug_rw_buf_size - 1) - len, " Interrupt Number : 0x%x\n" " Type of Interrupt : 0x%x\n" @@ -505,24 +504,53 @@ static int _disp_tz_interrupt_stats(void) tzdbg_ptr->int_num, (uint32_t)tzdbg_ptr->int_info, (uint8_t *)tzdbg_ptr->int_desc); - for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) { - len += snprintf(tzdbg.disp_buf + len, + for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) { + len += snprintf(tzdbg.disp_buf + len, (debug_rw_buf_size - 1) - len, " int_count on CPU # %d : %u\n", (uint32_t)j, (uint32_t)tzdbg_ptr->int_count[j]); - } - len += snprintf(tzdbg.disp_buf + len, debug_rw_buf_size - 1, - "\n"); + } + len += snprintf(tzdbg.disp_buf + len, + debug_rw_buf_size - 1, "\n"); - if (len > (debug_rw_buf_size - 1)) { - pr_warn("%s: Cannot fit all info into the buffer\n", + if (len > (debug_rw_buf_size - 1)) { + pr_warn("%s: Cannot fit all info into buf\n", __func__); - break; + break; + } + ptr += int_info_size; } + } else { + for (i = 0; i < (*num_int); i++) { + tzdbg_ptr_tz40 = (struct tzdbg_int_t_tz40 *)ptr; + len += snprintf(tzdbg.disp_buf + len, + (debug_rw_buf_size - 1) - len, + " Interrupt Number : 0x%x\n" + " Type of Interrupt : 0x%x\n" + " Description of interrupt : %s\n", + tzdbg_ptr_tz40->int_num, + (uint32_t)tzdbg_ptr_tz40->int_info, + (uint8_t *)tzdbg_ptr_tz40->int_desc); + for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) { + len += snprintf(tzdbg.disp_buf + len, + (debug_rw_buf_size - 1) - len, + " int_count on CPU # %d : %u\n", + (uint32_t)j, + (uint32_t)tzdbg_ptr_tz40->int_count[j]); + } + len += snprintf(tzdbg.disp_buf + len, + debug_rw_buf_size - 1, "\n"); - ptr += int_info_size; + if (len > (debug_rw_buf_size - 1)) { + pr_warn("%s: Cannot fit all info into buf\n", + __func__); + break; + } + ptr += int_info_size; + } } + tzdbg.stat[TZDBG_INTERRUPT].data = tzdbg.disp_buf; return len; } @@ -1015,6 +1043,33 @@ static int __update_hypdbg_base(struct platform_device *pdev, return 0; } +static void tzdbg_get_tz_version(void) +{ + uint32_t smc_id = 0; + uint32_t feature = 10; + struct qseecom_command_scm_resp resp = {0}; + struct scm_desc desc = {0}; + int ret = 0; + + if (!is_scm_armv8()) { + ret = scm_call(SCM_SVC_INFO, SCM_SVC_UTIL, &feature, + sizeof(feature), &resp, sizeof(resp)); + } else { + smc_id = TZ_INFO_GET_FEATURE_VERSION_ID; + desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID; + desc.args[0] = feature; + ret = scm_call2(smc_id, &desc); + resp.result = desc.ret[0]; + } + + if (ret) + pr_err("%s: scm_call to get tz version failed\n", + __func__); + else + tzdbg.tz_version = resp.result; + +} + /* * Driver functions */ @@ -1103,6 +1158,9 @@ static int tz_log_probe(struct platform_device *pdev) goto err; tzdbg_register_qsee_log_buf(); + + tzdbg_get_tz_version(); + return 0; err: kfree(tzdbg.diag_buf); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index c161eeda417b..267749a94c5a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -3704,9 +3704,15 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev, default: encoder->possible_crtcs = 0x3; break; + case 3: + encoder->possible_crtcs = 0x7; + break; case 4: encoder->possible_crtcs = 0xf; break; + case 5: + encoder->possible_crtcs = 0x1f; + break; case 6: encoder->possible_crtcs = 0x3f; break; diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 810c51d92b99..30672a3df8a9 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -58,13 +58,9 @@ bool ast_is_vga_enabled(struct drm_device *dev) /* TODO 1180 */ } else { ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT); - if (ch) { - ast_open_key(ast); - ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff); - return ch & 0x04; - } + return !!(ch & 0x01); } - return 0; + return false; } static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff }; @@ -375,8 +371,8 @@ void ast_post_gpu(struct drm_device *dev) pci_write_config_dword(ast->dev->pdev, 0x04, reg); ast_enable_vga(dev); - ast_enable_mmio(dev); ast_open_key(ast); + ast_enable_mmio(dev); ast_set_def_ext_reg(dev); if (ast->chip == AST2300 || ast->chip == AST2400) @@ -1630,12 +1626,44 @@ static void ast_init_dram_2300(struct drm_device *dev) temp |= 0x73; ast_write32(ast, 0x12008, temp); + param.dram_freq = 396; param.dram_type = AST_DDR3; + temp = ast_mindwm(ast, 0x1e6e2070); if (temp & 0x01000000) param.dram_type = AST_DDR2; - param.dram_chipid = ast->dram_type; - param.dram_freq = ast->mclk; - param.vram_size = ast->vram_size; + switch (temp & 0x18000000) { + case 0: + param.dram_chipid = AST_DRAM_512Mx16; + break; + default: + case 0x08000000: + param.dram_chipid = AST_DRAM_1Gx16; + break; + case 0x10000000: + param.dram_chipid = AST_DRAM_2Gx16; + break; + case 0x18000000: + param.dram_chipid = AST_DRAM_4Gx16; + break; + } + switch (temp & 0x0c) { + default: + case 0x00: + param.vram_size = AST_VIDMEM_SIZE_8M; + break; + + case 0x04: + param.vram_size = AST_VIDMEM_SIZE_16M; + break; + + case 0x08: + param.vram_size = AST_VIDMEM_SIZE_32M; + break; + + case 0x0c: + param.vram_size = AST_VIDMEM_SIZE_64M; + break; + } if (param.dram_type == AST_DDR3) { get_ddr3_info(ast, ¶m); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 1ac29d703c12..ea443fafb934 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -265,7 +265,7 @@ mode_fixup(struct drm_atomic_state *state) struct drm_connector *connector; struct drm_connector_state *conn_state; int i; - bool ret; + int ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!crtc_state->mode_changed && diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 7cb2815e815e..a3b96d691ac9 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1812,7 +1812,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) mgr->payloads[i].num_slots = req_payload.num_slots; } else if (mgr->payloads[i].num_slots) { mgr->payloads[i].num_slots = 0; - drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]); + drm_dp_destroy_payload_step1(mgr, port, mgr->payloads[i].vcpi, &mgr->payloads[i]); req_payload.payload_state = mgr->payloads[i].payload_state; mgr->payloads[i].start_slot = 0; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8c9ac021608f..cc1e16fd7e76 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -144,6 +144,9 @@ static struct edid_quirk { /* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */ { "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC }, + + /* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/ + { "ETR", 13896, EDID_QUIRK_FORCE_8BPC }, }; /* diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3f802163f7d4..e7c18519274a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6803,7 +6803,18 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv) { - I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); + u32 val; + + /* + * On driver load, a pipe may be active and driving a DSI display. + * Preserve DPOUNIT_CLOCK_GATE_DISABLE to avoid the pipe getting stuck + * (and never recovering) in this case. intel_dsi_post_disable() will + * clear it when we turn off the display. + */ + val = I915_READ(DSPCLK_GATE_D); + val &= DPOUNIT_CLOCK_GATE_DISABLE; + val |= VRHUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, val); /* * Disable trickle feed and enable pnd deadline calculation diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 63128d11767e..d1455fbc980e 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -750,7 +750,10 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, size = PAGE_ALIGN(size); + mutex_lock(&dev->struct_mutex); ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj); + mutex_unlock(&dev->struct_mutex); + if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 3176f301e7a8..14c0cfc58270 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -576,8 +576,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); - - if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) + else if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 04cec0da5d1e..8901228b5d5d 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -205,8 +205,8 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) } if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) || - x >= (crtc->x + crtc->mode.crtc_hdisplay) || - y >= (crtc->y + crtc->mode.crtc_vdisplay)) + x >= (crtc->x + crtc->mode.hdisplay) || + y >= (crtc->y + crtc->mode.vdisplay)) goto out_of_bounds; x += xorigin; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 4ae8b56b1847..037c38bb5333 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1621,7 +1621,6 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) struct ttm_buffer_object *bo; int ret = -EBUSY; int put_count; - uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM); spin_lock(&glob->lru_lock); list_for_each_entry(bo, &glob->swap_lru, swap) { @@ -1657,7 +1656,8 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) if (unlikely(ret != 0)) goto out; - if ((bo->mem.placement & swap_placement) != swap_placement) { + if (bo->mem.mem_type != TTM_PL_SYSTEM || + bo->ttm->caching_state != tt_cached) { struct ttm_mem_reg evict_mem; evict_mem = bo->mem; diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 63194a9a7189..57c191798699 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -219,7 +219,7 @@ int hv_init(void) /* See if the hypercall page is already set */ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC); + virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX); if (!virtaddr) goto cleanup; @@ -422,7 +422,7 @@ int hv_synic_alloc(void) goto err; } - for_each_online_cpu(cpu) { + for_each_present_cpu(cpu) { hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC); if (hv_context.event_dpc[cpu] == NULL) { pr_err("Unable to allocate event dpc\n"); @@ -461,6 +461,8 @@ int hv_synic_alloc(void) pr_err("Unable to allocate post msg page\n"); goto err; } + + INIT_LIST_HEAD(&hv_context.percpu_list[cpu]); } return 0; @@ -485,7 +487,7 @@ void hv_synic_free(void) int cpu; kfree(hv_context.hv_numa_map); - for_each_online_cpu(cpu) + for_each_present_cpu(cpu) hv_synic_free_cpu(cpu); } @@ -555,8 +557,6 @@ void hv_synic_init(void *arg) rdmsrl(HV_X64_MSR_VP_INDEX, vp_index); hv_context.vp_index[cpu] = (u32)vp_index; - INIT_LIST_HEAD(&hv_context.percpu_list[cpu]); - /* * Register the per-cpu clockevent source. */ diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index c37a71e13de0..1fb02dcbc500 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -61,6 +61,7 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data); static const char fcopy_devname[] = "vmbus/hv_fcopy"; static u8 *recv_buffer; static struct hvutil_transport *hvt; +static struct completion release_event; /* * This state maintains the version number registered by the daemon. */ @@ -312,12 +313,14 @@ static void fcopy_on_reset(void) if (cancel_delayed_work_sync(&fcopy_timeout_work)) fcopy_respond_to_host(HV_E_FAIL); + complete(&release_event); } int hv_fcopy_init(struct hv_util_service *srv) { recv_buffer = srv->recv_buffer; + init_completion(&release_event); /* * When this driver loads, the user level daemon that * processes the host requests may not yet be running. @@ -339,4 +342,5 @@ void hv_fcopy_deinit(void) fcopy_transaction.state = HVUTIL_DEVICE_DYING; cancel_delayed_work_sync(&fcopy_timeout_work); hvutil_transport_destroy(hvt); + wait_for_completion(&release_event); } diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 2a3420c4ca59..ce4d3a935491 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -86,6 +86,7 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); static const char kvp_devname[] = "vmbus/hv_kvp"; static u8 *recv_buffer; static struct hvutil_transport *hvt; +static struct completion release_event; /* * Register the kernel component with the user-level daemon. * As part of this registration, pass the LIC version number. @@ -682,6 +683,7 @@ static void kvp_on_reset(void) if (cancel_delayed_work_sync(&kvp_timeout_work)) kvp_respond_to_host(NULL, HV_E_FAIL); kvp_transaction.state = HVUTIL_DEVICE_INIT; + complete(&release_event); } int @@ -689,6 +691,7 @@ hv_kvp_init(struct hv_util_service *srv) { recv_buffer = srv->recv_buffer; + init_completion(&release_event); /* * When this driver loads, the user level daemon that * processes the host requests may not yet be running. @@ -711,4 +714,5 @@ void hv_kvp_deinit(void) cancel_delayed_work_sync(&kvp_timeout_work); cancel_work_sync(&kvp_sendkey_work); hvutil_transport_destroy(hvt); + wait_for_completion(&release_event); } diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 81882d4848bd..faad79ae318a 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -66,6 +66,7 @@ static int dm_reg_value; static const char vss_devname[] = "vmbus/hv_vss"; static __u8 *recv_buffer; static struct hvutil_transport *hvt; +static struct completion release_event; static void vss_send_op(struct work_struct *dummy); static void vss_timeout_func(struct work_struct *dummy); @@ -326,11 +327,13 @@ static void vss_on_reset(void) if (cancel_delayed_work_sync(&vss_timeout_work)) vss_respond_to_host(HV_E_FAIL); vss_transaction.state = HVUTIL_DEVICE_INIT; + complete(&release_event); } int hv_vss_init(struct hv_util_service *srv) { + init_completion(&release_event); if (vmbus_proto_version < VERSION_WIN8_1) { pr_warn("Integration service 'Backup (volume snapshot)'" " not supported on this host version.\n"); @@ -360,4 +363,5 @@ void hv_vss_deinit(void) cancel_delayed_work_sync(&vss_timeout_work); cancel_work_sync(&vss_send_op_work); hvutil_transport_destroy(hvt); + wait_for_completion(&release_event); } diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index bf2a1dd7cf15..7f98d9f527b9 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -1151,12 +1151,20 @@ static void i2c_msm_dma_xfer_unprepare(struct i2c_msm_ctrl *ctrl) buf_itr->dma_dir); } -static void i2c_msm_dma_callback_xfer_complete(void *dma_async_param) +static void i2c_msm_dma_callback_tx_complete(void *dma_async_param) { struct i2c_msm_ctrl *ctrl = dma_async_param; + complete(&ctrl->xfer.complete); } +static void i2c_msm_dma_callback_rx_complete(void *dma_async_param) +{ + struct i2c_msm_ctrl *ctrl = dma_async_param; + + complete(&ctrl->xfer.rx_complete); +} + /* * i2c_msm_dma_xfer_process: Queue transfers to DMA * @pre 1)QUP is in run state. 2) i2c_msm_dma_xfer_prepare() was called. @@ -1269,14 +1277,16 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) } /* callback defined for tx dma desc */ - dma_desc_tx->callback = i2c_msm_dma_callback_xfer_complete; + dma_desc_tx->callback = i2c_msm_dma_callback_tx_complete; dma_desc_tx->callback_param = ctrl; dmaengine_submit(dma_desc_tx); dma_async_issue_pending(tx->dma_chan); /* queue the rx dma desc */ dma_desc_rx = dmaengine_prep_slave_sg(rx->dma_chan, sg_rx, - sg_rx_itr - sg_rx, rx->dir, 0); + sg_rx_itr - sg_rx, rx->dir, + (SPS_IOVEC_FLAG_EOT | + SPS_IOVEC_FLAG_NWD)); if (dma_desc_rx < 0) { dev_err(ctrl->dev, "error dmaengine_prep_slave_sg rx:%ld\n", @@ -1285,6 +1295,8 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) goto dma_xfer_end; } + dma_desc_rx->callback = i2c_msm_dma_callback_rx_complete; + dma_desc_rx->callback_param = ctrl; dmaengine_submit(dma_desc_rx); dma_async_issue_pending(rx->dma_chan); @@ -1297,6 +1309,8 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) } ret = i2c_msm_xfer_wait_for_completion(ctrl, &ctrl->xfer.complete); + if (!ret && ctrl->xfer.rx_cnt) + i2c_msm_xfer_wait_for_completion(ctrl, &ctrl->xfer.rx_complete); dma_xfer_end: /* free scatter-gather lists */ @@ -2054,13 +2068,14 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, long time_left; int ret = 0; - time_left = wait_for_completion_timeout(complete, xfer->timeout); + time_left = wait_for_completion_timeout(complete, + xfer->timeout); if (!time_left) { xfer->err = I2C_MSM_ERR_TIMEOUT; i2c_msm_dbg_dump_diag(ctrl, false, 0, 0); ret = -EIO; i2c_msm_prof_evnt_add(ctrl, MSM_ERR, I2C_MSM_COMPLT_FL, - xfer->timeout, time_left, 0); + xfer->timeout, time_left, 0); } else { /* return an error if one detected by ISR */ if (xfer->err) @@ -2327,6 +2342,8 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) xfer->tx_ovrhd_cnt = 0; atomic_set(&xfer->event_cnt, 0); init_completion(&xfer->complete); + init_completion(&xfer->rx_complete); + xfer->cur_buf.is_init = false; xfer->cur_buf.msg_idx = 0; diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c index 57145ea72e90..537cca877f66 100644 --- a/drivers/iio/adc/qcom-rradc.c +++ b/drivers/iio/adc/qcom-rradc.c @@ -38,6 +38,7 @@ #define FG_ADC_RR_FAKE_BATT_HIGH_MSB 0x5B #define FG_ADC_RR_BATT_ID_CTRL 0x60 +#define FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV BIT(0) #define FG_ADC_RR_BATT_ID_TRIGGER 0x61 #define FG_ADC_RR_BATT_ID_TRIGGER_CTL BIT(0) #define FG_ADC_RR_BATT_ID_STS 0x62 @@ -163,11 +164,6 @@ #define FG_ADC_RR_DIE_TEMP_SLOPE 2 #define FG_ADC_RR_DIE_TEMP_OFFSET_MILLI_DEGC 25000 -#define FAB_ID_GF 0x30 -#define FAB_ID_SMIC 0x11 -#define FAB_ID_660_GF 0x0 -#define FAB_ID_660_TSMC 0x2 -#define FAB_ID_660_MX 0x3 #define FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV 1303168 #define FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C 3784 #define FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV 1338433 @@ -401,11 +397,11 @@ static int rradc_get_660_fab_coeff(struct rradc_chip *chip, int64_t *offset, int64_t *slope) { switch (chip->pmic_fab_id->fab_id) { - case FAB_ID_660_GF: + case PM660_FAB_ID_GF: *offset = FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV; *slope = FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C; break; - case FAB_ID_660_TSMC: + case PM660_FAB_ID_TSMC: *offset = FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV; *slope = FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C; break; @@ -421,11 +417,11 @@ static int rradc_get_8998_fab_coeff(struct rradc_chip *chip, int64_t *offset, int64_t *slope) { switch (chip->pmic_fab_id->fab_id) { - case FAB_ID_GF: + case PMI8998_FAB_ID_GF: *offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV; *slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C; break; - case FAB_ID_SMIC: + case PMI8998_FAB_ID_SMIC: *offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV; *slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C; break; @@ -753,6 +749,75 @@ static int rradc_read_channel_with_continuous_mode(struct rradc_chip *chip, return rc; } +static int rradc_enable_batt_id_channel(struct rradc_chip *chip, bool enable) +{ + int rc = 0; + + if (enable) { + rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CTRL, + FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV, + FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV); + if (rc < 0) { + pr_err("Enabling BATT ID channel failed:%d\n", rc); + return rc; + } + } else { + rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CTRL, + FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV, 0); + if (rc < 0) { + pr_err("Disabling BATT ID channel failed:%d\n", rc); + return rc; + } + } + + return rc; +} + +static int rradc_do_batt_id_conversion(struct rradc_chip *chip, + struct rradc_chan_prop *prop, u16 *data, u8 *buf) +{ + int rc = 0, ret = 0; + + rc = rradc_enable_batt_id_channel(chip, true); + if (rc < 0) { + pr_err("Enabling BATT ID channel failed:%d\n", rc); + return rc; + } + + rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER, + FG_ADC_RR_BATT_ID_TRIGGER_CTL, + FG_ADC_RR_BATT_ID_TRIGGER_CTL); + if (rc < 0) { + pr_err("BATT_ID trigger set failed:%d\n", rc); + ret = rc; + rc = rradc_enable_batt_id_channel(chip, false); + if (rc < 0) + pr_err("Disabling BATT ID channel failed:%d\n", rc); + return ret; + } + + rc = rradc_read_channel_with_continuous_mode(chip, prop, buf); + if (rc < 0) { + pr_err("Error reading in continuous mode:%d\n", rc); + ret = rc; + } + + rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER, + FG_ADC_RR_BATT_ID_TRIGGER_CTL, 0); + if (rc < 0) { + pr_err("BATT_ID trigger re-set failed:%d\n", rc); + ret = rc; + } + + rc = rradc_enable_batt_id_channel(chip, false); + if (rc < 0) { + pr_err("Disabling BATT ID channel failed:%d\n", rc); + ret = rc; + } + + return ret; +} + static int rradc_do_conversion(struct rradc_chip *chip, struct rradc_chan_prop *prop, u16 *data) { @@ -765,24 +830,9 @@ static int rradc_do_conversion(struct rradc_chip *chip, switch (prop->channel) { case RR_ADC_BATT_ID: - rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER, - FG_ADC_RR_BATT_ID_TRIGGER_CTL, - FG_ADC_RR_BATT_ID_TRIGGER_CTL); - if (rc < 0) { - pr_err("BATT_ID trigger set failed:%d\n", rc); - goto fail; - } - - rc = rradc_read_channel_with_continuous_mode(chip, prop, buf); - if (rc < 0) { - pr_err("Error reading in continuous mode:%d\n", rc); - goto fail; - } - - rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER, - FG_ADC_RR_BATT_ID_TRIGGER_CTL, 0); + rc = rradc_do_batt_id_conversion(chip, prop, data, buf); if (rc < 0) { - pr_err("BATT_ID trigger re-set failed:%d\n", rc); + pr_err("Battery ID conversion failed:%d\n", rc); goto fail; } break; diff --git a/drivers/iio/adc/qcom-tadc.c b/drivers/iio/adc/qcom-tadc.c index 9241288c1d43..054dfcc8556a 100644 --- a/drivers/iio/adc/qcom-tadc.c +++ b/drivers/iio/adc/qcom-tadc.c @@ -18,7 +18,12 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/power_supply.h> +#include <linux/pmic-voter.h> +#define USB_PRESENT_VOTER "USB_PRESENT_VOTER" +#define SLEEP_VOTER "SLEEP_VOTER" +#define SHUTDOWN_VOTER "SHUTDOWN_VOTER" #define TADC_REVISION1_REG 0x00 #define TADC_REVISION2_REG 0x01 #define TADC_REVISION3_REG 0x02 @@ -54,6 +59,7 @@ #define TADC_CH7_ADC_HI_REG(chip) (chip->tadc_base + 0x73) #define TADC_CH8_ADC_LO_REG(chip) (chip->tadc_base + 0x74) #define TADC_CH8_ADC_HI_REG(chip) (chip->tadc_base + 0x75) +#define TADC_ADC_DIRECT_TST(chip) (chip->tadc_base + 0xE7) /* TADC_CMP register definitions */ #define TADC_CMP_THR1_CMP_REG(chip) (chip->tadc_cmp_base + 0x51) @@ -217,6 +223,11 @@ struct tadc_chip { struct tadc_chan_data chans[TADC_NUM_CH]; struct completion eoc_complete; struct mutex write_lock; + struct mutex conv_lock; + struct power_supply *usb_psy; + struct votable *tadc_disable_votable; + struct work_struct status_change_work; + struct notifier_block nb; }; struct tadc_pt { @@ -274,7 +285,7 @@ static bool tadc_is_reg_locked(struct tadc_chip *chip, u16 reg) if ((reg & 0xFF00) == chip->tadc_cmp_base) return true; - if (reg == TADC_HWTRIG_CONV_CH_EN_REG(chip)) + if (reg >= TADC_HWTRIG_CONV_CH_EN_REG(chip)) return true; return false; @@ -480,12 +491,22 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc) { unsigned long timeout, timeleft; u8 val[TADC_NUM_CH * 2]; - int rc, i; + int rc = 0, i; + mutex_lock(&chip->conv_lock); rc = tadc_read(chip, TADC_MBG_ERR_REG(chip), val, 1); if (rc < 0) { pr_err("Couldn't read mbg error status rc=%d\n", rc); - return rc; + goto unlock; + } + + reinit_completion(&chip->eoc_complete); + + if (get_effective_result(chip->tadc_disable_votable)) { + /* leave it back in completed state */ + complete_all(&chip->eoc_complete); + rc = -ENODATA; + goto unlock; } if (val[0] != 0) { @@ -496,7 +517,7 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc) rc = tadc_write(chip, TADC_CONV_REQ_REG(chip), channels); if (rc < 0) { pr_err("Couldn't write conversion request rc=%d\n", rc); - return rc; + goto unlock; } timeout = msecs_to_jiffies(CONVERSION_TIMEOUT_MS); @@ -506,25 +527,34 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc) rc = tadc_read(chip, TADC_SW_CH_CONV_REG(chip), val, 1); if (rc < 0) { pr_err("Couldn't read conversion status rc=%d\n", rc); - return rc; + goto unlock; } + /* + * check one last time if the channel we are requesting + * has completed conversion + */ if (val[0] != channels) { - pr_err("Conversion timed out\n"); - return -ETIMEDOUT; + rc = -ETIMEDOUT; + goto unlock; } } rc = tadc_read(chip, TADC_CH1_ADC_LO_REG(chip), val, ARRAY_SIZE(val)); if (rc < 0) { pr_err("Couldn't read adc channels rc=%d\n", rc); - return rc; + goto unlock; } for (i = 0; i < TADC_NUM_CH; i++) adc[i] = (s16)(val[i * 2] | (u16)val[i * 2 + 1] << 8); - return jiffies_to_msecs(timeout - timeleft); + pr_debug("Conversion time for channels 0x%x = %dms\n", channels, + jiffies_to_msecs(timeout - timeleft)); + +unlock: + mutex_unlock(&chip->conv_lock); + return rc; } static int tadc_read_raw(struct iio_dev *indio_dev, @@ -593,12 +623,17 @@ static int tadc_read_raw(struct iio_dev *indio_dev, break; default: rc = tadc_do_conversion(chip, BIT(chan->channel), adc); - if (rc >= 0) - *val = adc[chan->channel]; + if (rc < 0) { + if (rc != -ENODATA) + pr_err("Couldn't read battery current and voltage channels rc=%d\n", + rc); + return rc; + } + *val = adc[chan->channel]; break; } - if (rc < 0) { + if (rc < 0 && rc != -ENODATA) { pr_err("Couldn't read channel %d\n", chan->channel); return rc; } @@ -630,7 +665,7 @@ static int tadc_read_raw(struct iio_dev *indio_dev, case TADC_BATT_P: rc = tadc_do_conversion(chip, BIT(TADC_BATT_I) | BIT(TADC_BATT_V), adc); - if (rc < 0) { + if (rc < 0 && rc != -ENODATA) { pr_err("Couldn't read battery current and voltage channels rc=%d\n", rc); return rc; @@ -641,7 +676,7 @@ static int tadc_read_raw(struct iio_dev *indio_dev, case TADC_INPUT_P: rc = tadc_do_conversion(chip, BIT(TADC_INPUT_I) | BIT(TADC_INPUT_V), adc); - if (rc < 0) { + if (rc < 0 && rc != -ENODATA) { pr_err("Couldn't read input current and voltage channels rc=%d\n", rc); return rc; @@ -683,6 +718,7 @@ static int tadc_read_raw(struct iio_dev *indio_dev, case TADC_DIE_TEMP: case TADC_DIE_TEMP_THR1: case TADC_DIE_TEMP_THR2: + case TADC_DIE_TEMP_THR3: *val = chan_data->scale; return IIO_VAL_INT; case TADC_BATT_I: @@ -821,15 +857,130 @@ static int tadc_write_raw(struct iio_dev *indio_dev, return 0; } - static irqreturn_t handle_eoc(int irq, void *dev_id) { struct tadc_chip *chip = dev_id; - complete(&chip->eoc_complete); + complete_all(&chip->eoc_complete); return IRQ_HANDLED; } +static int tadc_disable_vote_callback(struct votable *votable, + void *data, int disable, const char *client) +{ + struct tadc_chip *chip = data; + int rc; + int timeout; + unsigned long timeleft; + + if (disable) { + timeout = msecs_to_jiffies(CONVERSION_TIMEOUT_MS); + timeleft = wait_for_completion_timeout(&chip->eoc_complete, + timeout); + if (timeleft == 0) + pr_err("Timed out waiting for eoc, disabling hw conversions regardless\n"); + + rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x00); + if (rc < 0) { + pr_err("Couldn't disable hw conversions rc=%d\n", rc); + return rc; + } + rc = tadc_write(chip, TADC_ADC_DIRECT_TST(chip), 0x80); + if (rc < 0) { + pr_err("Couldn't enable direct test mode rc=%d\n", rc); + return rc; + } + } else { + rc = tadc_write(chip, TADC_ADC_DIRECT_TST(chip), 0x00); + if (rc < 0) { + pr_err("Couldn't disable direct test mode rc=%d\n", rc); + return rc; + } + rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x07); + if (rc < 0) { + pr_err("Couldn't enable hw conversions rc=%d\n", rc); + return rc; + } + } + + pr_debug("client: %s disable: %d\n", client, disable); + return 0; +} + +static void status_change_work(struct work_struct *work) +{ + struct tadc_chip *chip = container_of(work, + struct tadc_chip, status_change_work); + union power_supply_propval pval = {0, }; + int rc; + + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + + if (!chip->usb_psy) { + /* treat usb is not present */ + vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, true, 0); + return; + } + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + if (rc < 0) { + pr_err("Couldn't get present status rc=%d\n", rc); + /* treat usb is not present */ + vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, true, 0); + return; + } + + /* disable if usb is not present */ + vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, !pval.intval, 0); +} + +static int tadc_notifier_call(struct notifier_block *nb, + unsigned long ev, void *v) +{ + struct power_supply *psy = v; + struct tadc_chip *chip = container_of(nb, struct tadc_chip, nb); + + if (ev != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if ((strcmp(psy->desc->name, "usb") == 0)) + schedule_work(&chip->status_change_work); + + return NOTIFY_OK; +} + +static int tadc_register_notifier(struct tadc_chip *chip) +{ + int rc; + + chip->nb.notifier_call = tadc_notifier_call; + rc = power_supply_reg_notifier(&chip->nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + return rc; + } + + return 0; +} + +static int tadc_suspend(struct device *dev) +{ + struct tadc_chip *chip = dev_get_drvdata(dev); + + vote(chip->tadc_disable_votable, SLEEP_VOTER, true, 0); + return 0; +} + +static int tadc_resume(struct device *dev) +{ + struct tadc_chip *chip = dev_get_drvdata(dev); + + vote(chip->tadc_disable_votable, SLEEP_VOTER, false, 0); + return 0; +} + static int tadc_set_therm_table(struct tadc_chan_data *chan_data, u32 beta, u32 rtherm) { @@ -1009,6 +1160,12 @@ static int tadc_probe(struct platform_device *pdev) chip->dev = &pdev->dev; init_completion(&chip->eoc_complete); + /* + * set the completion in "completed" state so disable of the tadc + * can progress + */ + complete_all(&chip->eoc_complete); + rc = of_property_read_u32(node, "reg", &chip->tadc_base); if (rc < 0) { pr_err("Couldn't read base address rc=%d\n", rc); @@ -1017,6 +1174,8 @@ static int tadc_probe(struct platform_device *pdev) chip->tadc_cmp_base = chip->tadc_base + 0x100; mutex_init(&chip->write_lock); + mutex_init(&chip->conv_lock); + INIT_WORK(&chip->status_change_work, status_change_work); chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { pr_err("Couldn't get regmap\n"); @@ -1035,17 +1194,36 @@ static int tadc_probe(struct platform_device *pdev) return rc; } + chip->tadc_disable_votable = create_votable("SMB_TADC_DISABLE", + VOTE_SET_ANY, + tadc_disable_vote_callback, + chip); + if (IS_ERR(chip->tadc_disable_votable)) { + rc = PTR_ERR(chip->tadc_disable_votable); + return rc; + } + /* assume usb is not present */ + vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, true, 0); + vote(chip->tadc_disable_votable, SHUTDOWN_VOTER, false, 0); + vote(chip->tadc_disable_votable, SLEEP_VOTER, false, 0); + + rc = tadc_register_notifier(chip); + if (rc < 0) { + pr_err("Couldn't register notifier=%d\n", rc); + goto destroy_votable; + } + irq = of_irq_get_byname(node, "eoc"); if (irq < 0) { pr_err("Couldn't get eoc irq rc=%d\n", irq); - return irq; + goto destroy_votable; } rc = devm_request_threaded_irq(chip->dev, irq, NULL, handle_eoc, IRQF_ONESHOT, "eoc", chip); if (rc < 0) { pr_err("Couldn't request irq %d rc=%d\n", irq, rc); - return rc; + goto destroy_votable; } indio_dev->dev.parent = chip->dev; @@ -1058,17 +1236,37 @@ static int tadc_probe(struct platform_device *pdev) rc = devm_iio_device_register(chip->dev, indio_dev); if (rc < 0) { pr_err("Couldn't register IIO device rc=%d\n", rc); - return rc; + goto destroy_votable; } + platform_set_drvdata(pdev, chip); return 0; + +destroy_votable: + destroy_votable(chip->tadc_disable_votable); + return rc; } static int tadc_remove(struct platform_device *pdev) { + struct tadc_chip *chip = platform_get_drvdata(pdev); + + destroy_votable(chip->tadc_disable_votable); return 0; } +static void tadc_shutdown(struct platform_device *pdev) +{ + struct tadc_chip *chip = platform_get_drvdata(pdev); + + vote(chip->tadc_disable_votable, SHUTDOWN_VOTER, true, 0); +} + +static const struct dev_pm_ops tadc_pm_ops = { + .resume = tadc_resume, + .suspend = tadc_suspend, +}; + static const struct of_device_id tadc_match_table[] = { { .compatible = "qcom,tadc" }, { } @@ -1076,12 +1274,14 @@ static const struct of_device_id tadc_match_table[] = { MODULE_DEVICE_TABLE(of, tadc_match_table); static struct platform_driver tadc_driver = { - .driver = { + .driver = { .name = "qcom-tadc", .of_match_table = tadc_match_table, + .pm = &tadc_pm_ops, }, - .probe = tadc_probe, - .remove = tadc_remove, + .probe = tadc_probe, + .remove = tadc_remove, + .shutdown = tadc_shutdown, }; module_platform_driver(tadc_driver); diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index a0d7deeac62f..3f90985d545e 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -136,6 +136,7 @@ static const struct iio_chan_spec mpl115_channels[] = { { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), }, }; diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 01b2e0b18878..0f5b8767ec2e 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -182,7 +182,7 @@ static const struct iio_chan_spec mpl3115_channels[] = { { .type = IIO_PRESSURE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .scan_index = 0, .scan_type = { .sign = 'u', @@ -195,7 +195,7 @@ static const struct iio_chan_spec mpl3115_channels[] = { { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .scan_index = 1, .scan_type = { .sign = 's', diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index c9dcad6a53bf..3f5741a3e728 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -3349,6 +3349,9 @@ static int cma_accept_iw(struct rdma_id_private *id_priv, struct iw_cm_conn_param iw_param; int ret; + if (!conn_param) + return -EINVAL; + ret = cma_modify_qp_rtr(id_priv, conn_param); if (ret) return ret; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 3ba7de5f9379..2018d24344de 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1488,12 +1488,14 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, ret = ipoib_set_mode(dev, buf); - rtnl_unlock(); - - if (!ret) - return count; + /* The assumption is that the function ipoib_set_mode returned + * with the rtnl held by it, if not the value -EBUSY returned, + * then no need to rtnl_unlock + */ + if (ret != -EBUSY) + rtnl_unlock(); - return ret; + return (!ret || ret == -EBUSY) ? count : ret; } static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 8a4d10452d61..8efcff1beb8f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -464,8 +464,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf) priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM; ipoib_flush_paths(dev); - rtnl_lock(); - return 0; + return (!rtnl_trylock()) ? -EBUSY : 0; } if (!strcmp(buf, "datagram\n")) { @@ -474,8 +473,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf) dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); rtnl_unlock(); ipoib_flush_paths(dev); - rtnl_lock(); - return 0; + return (!rtnl_trylock()) ? -EBUSY : 0; } return -EINVAL; @@ -628,6 +626,14 @@ void ipoib_mark_paths_invalid(struct net_device *dev) spin_unlock_irq(&priv->lock); } +static void push_pseudo_header(struct sk_buff *skb, const char *daddr) +{ + struct ipoib_pseudo_header *phdr; + + phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr)); + memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); +} + void ipoib_flush_paths(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -852,8 +858,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { - /* put pseudoheader back on for next time */ - skb_push(skb, IPOIB_PSEUDO_LEN); + push_pseudo_header(skb, neigh->daddr); __skb_queue_tail(&neigh->queue, skb); } else { ipoib_warn(priv, "queue length limit %d. Packet drop.\n", @@ -871,10 +876,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, if (!path->query && path_rec_start(dev, path)) goto err_path; - if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) + if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { + push_pseudo_header(skb, neigh->daddr); __skb_queue_tail(&neigh->queue, skb); - else + } else { goto err_drop; + } } spin_unlock_irqrestore(&priv->lock, flags); @@ -910,8 +917,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, } if (path) { if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { - /* put pseudoheader back on for next time */ - skb_push(skb, IPOIB_PSEUDO_LEN); + push_pseudo_header(skb, phdr->hwaddr); __skb_queue_tail(&path->queue, skb); } else { ++dev->stats.tx_dropped; @@ -943,8 +949,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, return; } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { - /* put pseudoheader back on for next time */ - skb_push(skb, IPOIB_PSEUDO_LEN); + push_pseudo_header(skb, phdr->hwaddr); __skb_queue_tail(&path->queue, skb); } else { ++dev->stats.tx_dropped; @@ -1025,8 +1030,7 @@ send_using_neigh: } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { - /* put pseudoheader back on for next time */ - skb_push(skb, sizeof(*phdr)); + push_pseudo_header(skb, phdr->hwaddr); spin_lock_irqsave(&priv->lock, flags); __skb_queue_tail(&neigh->queue, skb); spin_unlock_irqrestore(&priv->lock, flags); @@ -1058,7 +1062,6 @@ static int ipoib_hard_header(struct sk_buff *skb, unsigned short type, const void *daddr, const void *saddr, unsigned len) { - struct ipoib_pseudo_header *phdr; struct ipoib_header *header; header = (struct ipoib_header *) skb_push(skb, sizeof *header); @@ -1071,8 +1074,7 @@ static int ipoib_hard_header(struct sk_buff *skb, * destination address into skb hard header so we can figure out where * to send the packet later. */ - phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr)); - memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); + push_pseudo_header(skb, daddr); return IPOIB_HARD_LEN; } diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5f0f4fc58f43..e397f1b0af09 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1787,17 +1787,24 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { spin_lock_irqsave(&ch->lock, flags); ch->req_lim += be32_to_cpu(rsp->req_lim_delta); + if (rsp->tag == ch->tsk_mgmt_tag) { + ch->tsk_mgmt_status = -1; + if (be32_to_cpu(rsp->resp_data_len) >= 4) + ch->tsk_mgmt_status = rsp->data[3]; + complete(&ch->tsk_mgmt_done); + } else { + shost_printk(KERN_ERR, target->scsi_host, + "Received tsk mgmt response too late for tag %#llx\n", + rsp->tag); + } spin_unlock_irqrestore(&ch->lock, flags); - - ch->tsk_mgmt_status = -1; - if (be32_to_cpu(rsp->resp_data_len) >= 4) - ch->tsk_mgmt_status = rsp->data[3]; - complete(&ch->tsk_mgmt_done); } else { scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag); - if (scmnd) { + if (scmnd && scmnd->host_scribble) { req = (void *)scmnd->host_scribble; scmnd = srp_claim_req(ch, req, NULL, scmnd); + } else { + scmnd = NULL; } if (!scmnd) { shost_printk(KERN_ERR, target->scsi_host, @@ -2469,19 +2476,18 @@ srp_change_queue_depth(struct scsi_device *sdev, int qdepth) } static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun, - u8 func) + u8 func, u8 *status) { struct srp_target_port *target = ch->target; struct srp_rport *rport = target->rport; struct ib_device *dev = target->srp_host->srp_dev->dev; struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; + int res; if (!ch->connected || target->qp_in_error) return -1; - init_completion(&ch->tsk_mgmt_done); - /* * Lock the rport mutex to avoid that srp_create_ch_ib() is * invoked while a task management function is being sent. @@ -2504,10 +2510,16 @@ static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun, tsk_mgmt->opcode = SRP_TSK_MGMT; int_to_scsilun(lun, &tsk_mgmt->lun); - tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT; tsk_mgmt->tsk_mgmt_func = func; tsk_mgmt->task_tag = req_tag; + spin_lock_irq(&ch->lock); + ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT; + tsk_mgmt->tag = ch->tsk_mgmt_tag; + spin_unlock_irq(&ch->lock); + + init_completion(&ch->tsk_mgmt_done); + ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, DMA_TO_DEVICE); if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) { @@ -2516,13 +2528,15 @@ static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun, return -1; } + res = wait_for_completion_timeout(&ch->tsk_mgmt_done, + msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)); + if (res > 0 && status) + *status = ch->tsk_mgmt_status; mutex_unlock(&rport->mutex); - if (!wait_for_completion_timeout(&ch->tsk_mgmt_done, - msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) - return -1; + WARN_ON_ONCE(res < 0); - return 0; + return res > 0 ? 0 : -1; } static int srp_abort(struct scsi_cmnd *scmnd) @@ -2548,7 +2562,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) shost_printk(KERN_ERR, target->scsi_host, "Sending SRP abort for tag %#x\n", tag); if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun, - SRP_TSK_ABORT_TASK) == 0) + SRP_TSK_ABORT_TASK, NULL) == 0) ret = SUCCESS; else if (target->rport->state == SRP_RPORT_LOST) ret = FAST_IO_FAIL; @@ -2566,14 +2580,15 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_rdma_ch *ch; int i; + u8 status; shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); ch = &target->ch[0]; if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun, - SRP_TSK_LUN_RESET)) + SRP_TSK_LUN_RESET, &status)) return FAILED; - if (ch->tsk_mgmt_status) + if (status) return FAILED; for (i = 0; i < target->ch_count; i++) { diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index f6af531f9f32..109eea94d0f9 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -168,6 +168,7 @@ struct srp_rdma_ch { int max_ti_iu_len; int comp_vector; + u64 tsk_mgmt_tag; struct completion tsk_mgmt_done; u8 tsk_mgmt_status; bool connected; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index cf29f2756b84..c93dd193a496 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -3,6 +3,7 @@ * * Copyright 2005 Phil Blundell * Copyright 2010, 2011 David Jander <david@protonic.nl> + * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,6 +33,7 @@ #include <linux/of_irq.h> #include <linux/spinlock.h> #include <linux/pinctrl/consumer.h> +#include <linux/syscore_ops.h> struct gpio_button_data { const struct gpio_keys_button *button; @@ -57,6 +59,11 @@ struct gpio_keys_drvdata { struct gpio_button_data data[0]; }; +static struct device *global_dev; +static struct syscore_ops gpio_keys_syscore_pm_ops; + +static void gpio_keys_syscore_resume(void); + /* * SYSFS interface for enabling/disabling keys and switches: * @@ -343,14 +350,14 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) const struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = gpio_get_value_cansleep(button->gpio); + int state; + state = (__gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; if (state < 0) { dev_err(input->dev.parent, "failed to get gpio state\n"); return; } - state = (state ? 1 : 0) ^ button->active_low; if (type == EV_ABS) { if (state) input_event(input, type, button->code, button->value); @@ -664,6 +671,8 @@ gpio_keys_get_devtree_pdata(struct device *dev) pdata->nbuttons = nbuttons; pdata->rep = !!of_get_property(node, "autorepeat", NULL); + pdata->name = of_get_property(node, "input-name", NULL); + pdata->use_syscore = of_property_read_bool(node, "use-syscore"); i = 0; for_each_child_of_node(node, pp) { @@ -710,7 +719,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); if (of_property_read_u32(pp, "debounce-interval", - &button->debounce_interval)) + &button->debounce_interval)) button->debounce_interval = 5; } @@ -767,6 +776,7 @@ static int gpio_keys_probe(struct platform_device *pdev) return -ENOMEM; } + global_dev = dev; ddata->pdata = pdata; ddata->input = input; mutex_init(&ddata->disable_lock); @@ -835,6 +845,11 @@ static int gpio_keys_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, wakeup); + if (pdata->use_syscore) + gpio_keys_syscore_pm_ops.resume = gpio_keys_syscore_resume; + + register_syscore_ops(&gpio_keys_syscore_pm_ops); + return 0; err_remove_group: @@ -857,6 +872,7 @@ err_setup_key: static int gpio_keys_remove(struct platform_device *pdev) { sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); + unregister_syscore_ops(&gpio_keys_syscore_pm_ops); device_init_wakeup(&pdev->dev, 0); @@ -864,6 +880,41 @@ static int gpio_keys_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP +static void gpio_keys_syscore_resume(void) +{ + struct gpio_keys_drvdata *ddata = dev_get_drvdata(global_dev); + struct input_dev *input = ddata->input; + struct gpio_button_data *bdata = NULL; + int error = 0; + int i; + + if (ddata->key_pinctrl) { + error = gpio_keys_pinctrl_configure(ddata, true); + if (error) { + dev_err(global_dev, "failed to put the pin in resume state\n"); + return; + } + } + + if (device_may_wakeup(global_dev)) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { + bdata = &ddata->data[i]; + if (bdata->button->wakeup) + disable_irq_wake(bdata->irq); + } + } else { + mutex_lock(&input->mutex); + if (input->users) + error = gpio_keys_open(input); + mutex_unlock(&input->mutex); + } + + if (error) + return; + + gpio_keys_report_state(ddata); +} + static int gpio_keys_suspend(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); @@ -901,6 +952,11 @@ static int gpio_keys_resume(struct device *dev) int error = 0; int i; + if (ddata->pdata->use_syscore == true) { + dev_dbg(global_dev, "Using syscore resume, no need of this resume.\n"); + return 0; + } + if (ddata->key_pinctrl) { error = gpio_keys_pinctrl_configure(ddata, true); if (error) { @@ -928,6 +984,21 @@ static int gpio_keys_resume(struct device *dev) gpio_keys_report_state(ddata); return 0; } + +#else + +static void gpio_keys_syscore_resume(void){} + +static int gpio_keys_suspend(struct device *dev) +{ + return 0; +} + +static int gpio_keys_resume(struct device *dev) +{ + return 0; +} + #endif static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d15b33813021..ed1935f300a7 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1232,6 +1232,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0000", 0 }, { "ELAN0100", 0 }, { "ELAN0600", 0 }, + { "ELAN0605", 0 }, { "ELAN1000", 0 }, { } }; diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c index 206941708141..3e85cb5e2ebc 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c @@ -3666,7 +3666,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) return -EINVAL; } - rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL); + rmi4_data = devm_kzalloc(&pdev->dev, sizeof(*rmi4_data), GFP_KERNEL); if (!rmi4_data) { dev_err(&pdev->dev, "%s: Failed to alloc mem for rmi4_data\n", @@ -3684,6 +3684,12 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) rmi4_data->fingers_on_2d = false; rmi4_data->update_coords = true; + rmi4_data->write_buf = devm_kzalloc(&pdev->dev, I2C_WRITE_BUF_MAX_LEN, + GFP_KERNEL); + if (!rmi4_data->write_buf) + return -ENOMEM; + rmi4_data->write_buf_len = I2C_WRITE_BUF_MAX_LEN; + rmi4_data->irq_enable = synaptics_rmi4_irq_enable; rmi4_data->reset_device = synaptics_rmi4_reset_device; diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h index 7d7e045d7917..a642092e2f63 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h @@ -101,6 +101,7 @@ #define PINCTRL_STATE_RELEASE "pmx_ts_release" #define SYNA_FW_NAME_MAX_LEN 50 +#define I2C_WRITE_BUF_MAX_LEN 32 enum exp_fn { RMI_DEV = 0, @@ -277,6 +278,8 @@ struct synaptics_rmi4_data { unsigned char no_sleep_setting; unsigned char intr_mask[MAX_INTR_REGISTERS]; unsigned char *button_txrx_mapping; + unsigned char *write_buf; + unsigned short write_buf_len; unsigned short num_of_intr_regs; unsigned short f01_query_base_addr; unsigned short f01_cmd_base_addr; diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c index 0b3fbaf9f462..0be7e0bc9045 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c @@ -134,18 +134,33 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, { int retval; unsigned char retry; - unsigned char buf[length + 1]; struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); struct i2c_msg msg[] = { { .addr = i2c->addr, .flags = 0, .len = length + 1, - .buf = buf, } }; mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); + /* + * Reassign memory for write_buf in case length is greater than 32 bytes + */ + if (rmi4_data->write_buf_len < length + 1) { + devm_kfree(rmi4_data->pdev->dev.parent, rmi4_data->write_buf); + rmi4_data->write_buf = devm_kzalloc(rmi4_data->pdev->dev.parent, + length + 1, GFP_KERNEL); + if (!rmi4_data->write_buf) { + rmi4_data->write_buf_len = 0; + retval = -ENOMEM; + goto exit; + } + rmi4_data->write_buf_len = length + 1; + } + + /* Assign the write_buf of driver structure to i2c_msg buf */ + msg[0].buf = rmi4_data->write_buf; retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr); if (retval != PAGE_SELECT_LEN) { @@ -153,8 +168,8 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, goto exit; } - buf[0] = addr & MASK_8BIT; - memcpy(&buf[1], &data[0], length); + rmi4_data->write_buf[0] = addr & MASK_8BIT; + memcpy(&rmi4_data->write_buf[1], &data[0], length); for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { if (i2c_transfer(i2c->adapter, msg, 1) == 1) { diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 9413b0726237..f0fc6f7b5d98 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3238,13 +3238,14 @@ static int __init init_dmars(void) iommu_identity_mapping |= IDENTMAP_GFX; #endif + check_tylersburg_isoch(); + if (iommu_identity_mapping) { ret = si_domain_init(hw_pass_through); if (ret) goto free_iommu; } - check_tylersburg_isoch(); /* * If we copied translations from a previous kernel in the kdump diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 6b420a55c745..c3ea03c9a1a8 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -425,7 +425,7 @@ struct cache { * until a gc finishes - otherwise we could pointlessly burn a ton of * cpu */ - unsigned invalidate_needs_gc:1; + unsigned invalidate_needs_gc; bool discard; /* Get rid of? */ @@ -593,8 +593,8 @@ struct cache_set { /* Counts how many sectors bio_insert has added to the cache */ atomic_t sectors_to_gc; + wait_queue_head_t gc_wait; - wait_queue_head_t moving_gc_wait; struct keybuf moving_gc_keys; /* Number of moving GC bios in flight */ struct semaphore moving_in_flight; diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 22b9e34ceb75..5b815e64c1c9 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -1762,33 +1762,34 @@ static void bch_btree_gc(struct cache_set *c) bch_moving_gc(c); } -static int bch_gc_thread(void *arg) +static bool gc_should_run(struct cache_set *c) { - struct cache_set *c = arg; struct cache *ca; unsigned i; - while (1) { -again: - bch_btree_gc(c); + for_each_cache(ca, c, i) + if (ca->invalidate_needs_gc) + return true; - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) - break; + if (atomic_read(&c->sectors_to_gc) < 0) + return true; - mutex_lock(&c->bucket_lock); + return false; +} - for_each_cache(ca, c, i) - if (ca->invalidate_needs_gc) { - mutex_unlock(&c->bucket_lock); - set_current_state(TASK_RUNNING); - goto again; - } +static int bch_gc_thread(void *arg) +{ + struct cache_set *c = arg; - mutex_unlock(&c->bucket_lock); + while (1) { + wait_event_interruptible(c->gc_wait, + kthread_should_stop() || gc_should_run(c)); - try_to_freeze(); - schedule(); + if (kthread_should_stop()) + break; + + set_gc_sectors(c); + bch_btree_gc(c); } return 0; @@ -1796,11 +1797,10 @@ again: int bch_gc_thread_start(struct cache_set *c) { - c->gc_thread = kthread_create(bch_gc_thread, c, "bcache_gc"); + c->gc_thread = kthread_run(bch_gc_thread, c, "bcache_gc"); if (IS_ERR(c->gc_thread)) return PTR_ERR(c->gc_thread); - set_task_state(c->gc_thread, TASK_INTERRUPTIBLE); return 0; } diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h index 5c391fa01bed..9b80417cd547 100644 --- a/drivers/md/bcache/btree.h +++ b/drivers/md/bcache/btree.h @@ -260,8 +260,7 @@ void bch_initial_mark_key(struct cache_set *, int, struct bkey *); static inline void wake_up_gc(struct cache_set *c) { - if (c->gc_thread) - wake_up_process(c->gc_thread); + wake_up(&c->gc_wait); } #define MAP_DONE 0 diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 25fa8445bb24..2410df1c2a05 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -196,10 +196,8 @@ static void bch_data_insert_start(struct closure *cl) struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); struct bio *bio = op->bio, *n; - if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) { - set_gc_sectors(op->c); + if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) wake_up_gc(op->c); - } if (op->bypass) return bch_data_invalidate(cl); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 3d5c0ba13181..7b5880b8874c 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1489,6 +1489,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb) mutex_init(&c->bucket_lock); init_waitqueue_head(&c->btree_cache_wait); init_waitqueue_head(&c->bucket_wait); + init_waitqueue_head(&c->gc_wait); sema_init(&c->uuid_write_mutex, 1); spin_lock_init(&c->btree_gc_time.lock); @@ -1547,6 +1548,7 @@ static void run_cache_set(struct cache_set *c) for_each_cache(ca, c, i) c->nbuckets += ca->sb.nbuckets; + set_gc_sectors(c); if (CACHE_SYNC(&c->sb)) { LIST_HEAD(journal); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index bb9b92ebbf8e..0da5efaad85c 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -248,7 +248,7 @@ struct cache { /* * Fields for converting from sectors to blocks. */ - uint32_t sectors_per_block; + sector_t sectors_per_block; int sectors_per_block_shift; spinlock_t lock; @@ -3544,11 +3544,11 @@ static void cache_status(struct dm_target *ti, status_type_t type, residency = policy_residency(cache->policy); - DMEMIT("%u %llu/%llu %u %llu/%llu %u %u %u %u %u %u %lu ", + DMEMIT("%u %llu/%llu %llu %llu/%llu %u %u %u %u %u %u %lu ", (unsigned)DM_CACHE_METADATA_BLOCK_SIZE, (unsigned long long)(nr_blocks_metadata - nr_free_blocks_metadata), (unsigned long long)nr_blocks_metadata, - cache->sectors_per_block, + (unsigned long long)cache->sectors_per_block, (unsigned long long) from_cblock(residency), (unsigned long long) from_cblock(cache->cache_size), (unsigned) atomic_read(&cache->stats.read_hit), diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index 8289804ccd99..d5ea9f28ae70 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -175,6 +175,7 @@ static void dm_stat_free(struct rcu_head *head) int cpu; struct dm_stat *s = container_of(head, struct dm_stat, rcu_head); + kfree(s->histogram_boundaries); kfree(s->program_id); kfree(s->aux_data); for_each_possible_cpu(cpu) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index dd1cde5458b8..e9b34de2319e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1467,11 +1467,62 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors) } EXPORT_SYMBOL_GPL(dm_accept_partial_bio); +/* + * Flush current->bio_list when the target map method blocks. + * This fixes deadlocks in snapshot and possibly in other targets. + */ +struct dm_offload { + struct blk_plug plug; + struct blk_plug_cb cb; +}; + +static void flush_current_bio_list(struct blk_plug_cb *cb, bool from_schedule) +{ + struct dm_offload *o = container_of(cb, struct dm_offload, cb); + struct bio_list list; + struct bio *bio; + + INIT_LIST_HEAD(&o->cb.list); + + if (unlikely(!current->bio_list)) + return; + + list = *current->bio_list; + bio_list_init(current->bio_list); + + while ((bio = bio_list_pop(&list))) { + struct bio_set *bs = bio->bi_pool; + if (unlikely(!bs) || bs == fs_bio_set) { + bio_list_add(current->bio_list, bio); + continue; + } + + spin_lock(&bs->rescue_lock); + bio_list_add(&bs->rescue_list, bio); + queue_work(bs->rescue_workqueue, &bs->rescue_work); + spin_unlock(&bs->rescue_lock); + } +} + +static void dm_offload_start(struct dm_offload *o) +{ + blk_start_plug(&o->plug); + o->cb.callback = flush_current_bio_list; + list_add(&o->cb.list, ¤t->plug->cb_list); +} + +static void dm_offload_end(struct dm_offload *o) +{ + list_del(&o->cb.list); + blk_finish_plug(&o->plug); +} + static void __map_bio(struct dm_target_io *tio) { int r; sector_t sector; struct mapped_device *md; + struct dm_offload o; struct bio *clone = &tio->clone; struct dm_target *ti = tio->ti; @@ -1484,7 +1535,11 @@ static void __map_bio(struct dm_target_io *tio) */ atomic_inc(&tio->io->io_count); sector = clone->bi_iter.bi_sector; + + dm_offload_start(&o); r = ti->type->map(ti, clone); + dm_offload_end(&o); + if (r == DM_MAPIO_REMAPPED) { /* the bio has been remapped so dispatch it */ diff --git a/drivers/md/linear.c b/drivers/md/linear.c index b7fe7e9fc777..6ba3227e29b2 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -52,18 +52,26 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector) return conf->disks + lo; } +/* + * In linear_congested() conf->raid_disks is used as a copy of + * mddev->raid_disks to iterate conf->disks[], because conf->raid_disks + * and conf->disks[] are created in linear_conf(), they are always + * consitent with each other, but mddev->raid_disks does not. + */ static int linear_congested(struct mddev *mddev, int bits) { struct linear_conf *conf; int i, ret = 0; - conf = mddev->private; + rcu_read_lock(); + conf = rcu_dereference(mddev->private); - for (i = 0; i < mddev->raid_disks && !ret ; i++) { + for (i = 0; i < conf->raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev); ret |= bdi_congested(&q->backing_dev_info, bits); } + rcu_read_unlock(); return ret; } @@ -143,6 +151,19 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks) conf->disks[i-1].end_sector + conf->disks[i].rdev->sectors; + /* + * conf->raid_disks is copy of mddev->raid_disks. The reason to + * keep a copy of mddev->raid_disks in struct linear_conf is, + * mddev->raid_disks may not be consistent with pointers number of + * conf->disks[] when it is updated in linear_add() and used to + * iterate old conf->disks[] earray in linear_congested(). + * Here conf->raid_disks is always consitent with number of + * pointers in conf->disks[] array, and mddev->private is updated + * with rcu_assign_pointer() in linear_addr(), such race can be + * avoided. + */ + conf->raid_disks = raid_disks; + return conf; out: @@ -195,15 +216,23 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev) if (!newconf) return -ENOMEM; + /* newconf->raid_disks already keeps a copy of * the increased + * value of mddev->raid_disks, WARN_ONCE() is just used to make + * sure of this. It is possible that oldconf is still referenced + * in linear_congested(), therefore kfree_rcu() is used to free + * oldconf until no one uses it anymore. + */ mddev_suspend(mddev); - oldconf = mddev->private; + oldconf = rcu_dereference(mddev->private); mddev->raid_disks++; - mddev->private = newconf; + WARN_ONCE(mddev->raid_disks != newconf->raid_disks, + "copied raid_disks doesn't match mddev->raid_disks"); + rcu_assign_pointer(mddev->private, newconf); md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); set_capacity(mddev->gendisk, mddev->array_sectors); mddev_resume(mddev); revalidate_disk(mddev->gendisk); - kfree(oldconf); + kfree_rcu(oldconf, rcu); return 0; } diff --git a/drivers/md/linear.h b/drivers/md/linear.h index b685ddd7d7f7..8d392e6098b3 100644 --- a/drivers/md/linear.h +++ b/drivers/md/linear.h @@ -10,6 +10,7 @@ struct linear_conf { struct rcu_head rcu; sector_t array_sectors; + int raid_disks; /* a copy of mddev->raid_disks */ struct dev_info disks[0]; }; #endif diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig index 173daf0c0847..14fa7e40f2a6 100644 --- a/drivers/media/pci/dm1105/Kconfig +++ b/drivers/media/pci/dm1105/Kconfig @@ -1,6 +1,6 @@ config DVB_DM1105 tristate "SDMC DM1105 based PCI cards" - depends on DVB_CORE && PCI && I2C + depends on DVB_CORE && PCI && I2C && I2C_ALGOBIT select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index ba780c45f645..572bc043b62d 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1576,7 +1576,7 @@ static int vpfe_s_fmt(struct file *file, void *priv, return -EBUSY; } - ret = vpfe_try_fmt(file, priv, &format); + ret = __vpfe_get_format(vpfe, &format, &bpp); if (ret) return ret; diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c index 3985df780216..df0664b496ba 100644 --- a/drivers/media/platform/msm/camera_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_v2/camera/camera.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -486,6 +486,9 @@ static long camera_v4l2_vidioc_private_ioctl(struct file *filep, void *fh, if (WARN_ON(!k_ioctl || !pvdev)) return -EIO; + if (cmd != VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD) + return -EINVAL; + switch (k_ioctl->id) { case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: { struct msm_camera_return_buf ptr, *tmp = NULL; diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c index 34fffa8dd7ce..a0c606ce9a29 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -376,18 +376,17 @@ int msm_camera_clk_enable(struct device *dev, if (clk_rate == 0) { clk_rate = clk_round_rate(clk_ptr[i], 0); - if (clk_rate < 0) { + if (clk_rate <= 0) { pr_err("%s round rate failed\n", clk_info[i].clk_name); goto cam_clk_set_err; } - rc = clk_set_rate(clk_ptr[i], - clk_rate); - if (rc < 0) { - pr_err("%s set rate failed\n", - clk_info[i].clk_name); - goto cam_clk_set_err; - } + } + rc = clk_set_rate(clk_ptr[i], clk_rate); + if (rc < 0) { + pr_err("%s set rate failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; } } rc = clk_prepare_enable(clk_ptr[i]); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 0325c5ded3cf..45c2dd588bc9 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -162,6 +162,8 @@ struct msm_vfe_irq_ops { void (*config_irq)(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, enum msm_isp_irq_operation); + void (*preprocess_camif_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0); }; struct msm_vfe_axi_ops { @@ -282,7 +284,7 @@ struct msm_vfe_stats_ops { void (*update_ping_pong_addr)(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr); + uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size); uint32_t (*get_frame_id)(struct vfe_device *vfe_dev); uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1); @@ -494,6 +496,7 @@ struct msm_vfe_src_info { struct timeval time_stamp; enum msm_vfe_dual_hw_type dual_hw_type; struct msm_vfe_dual_hw_ms_info dual_hw_ms_info; + bool accept_frame; }; struct msm_vfe_fetch_engine_info { @@ -767,6 +770,7 @@ struct vfe_device { struct msm_cam_clk_info *hvx_clk_info; size_t num_hvx_clk; size_t num_norm_clk; + bool hvx_clk_state; enum cam_ahb_clk_vote ahb_vote; struct cx_ipeak_client *vfe_cx_ipeak; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index bf18fc59585c..caf69af25601 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1305,7 +1305,7 @@ static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, - dma_addr_t paddr) + dma_addr_t paddr, uint32_t buf_sz) { void __iomem *vfe_base = vfe_dev->vfe_base; int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 8e549c338bdd..f5533fd9062e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2114,7 +2114,7 @@ static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev, static void msm_vfe40_stats_update_ping_pong_addr( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr) + uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz) { void __iomem *vfe_base = vfe_dev->vfe_base; int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, @@ -2218,6 +2218,7 @@ struct msm_vfe_hardware_info vfe40_hw_info = { .process_stats_irq = msm_isp_process_stats_irq, .process_epoch_irq = msm_vfe40_process_epoch_irq, .config_irq = msm_vfe40_config_irq, + .preprocess_camif_irq = msm_isp47_preprocess_camif_irq, }, .axi_ops = { .reload_wm = msm_vfe40_axi_reload_wm, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index 957cbc292be3..c85bf1655b8c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1720,7 +1720,7 @@ static void msm_vfe44_stats_update_cgc_override(struct vfe_device *vfe_dev, static void msm_vfe44_stats_update_ping_pong_addr( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr) + uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz) { void __iomem *vfe_base = vfe_dev->vfe_base; int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, @@ -1825,6 +1825,7 @@ struct msm_vfe_hardware_info vfe44_hw_info = { .process_stats_irq = msm_isp_process_stats_irq, .process_epoch_irq = msm_vfe44_process_epoch_irq, .config_irq = msm_vfe44_config_irq, + .preprocess_camif_irq = msm_isp47_preprocess_camif_irq, }, .axi_ops = { .reload_wm = msm_vfe44_axi_reload_wm, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index cc768db875db..72ce32940c29 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1798,7 +1798,7 @@ static void msm_vfe46_stats_enable_module(struct vfe_device *vfe_dev, static void msm_vfe46_stats_update_ping_pong_addr( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr) + uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz) { void __iomem *vfe_base = vfe_dev->vfe_base; int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, @@ -1902,6 +1902,7 @@ struct msm_vfe_hardware_info vfe46_hw_info = { .process_stats_irq = msm_isp_process_stats_irq, .process_epoch_irq = msm_vfe46_process_epoch_irq, .config_irq = msm_vfe46_config_irq, + .preprocess_camif_irq = msm_isp47_preprocess_camif_irq, }, .axi_ops = { .reload_wm = msm_vfe46_axi_reload_wm, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index b351e0e765a9..9c74695a6e32 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -386,6 +386,7 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev) vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks( vfe_dev, 0); + msm_vfe47_configure_hvx(vfe_dev, 0); vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0); } @@ -488,7 +489,7 @@ void msm_vfe47_process_violation_status( return; } - pr_err("%s: VFE pipeline violation status %d\n", __func__, + pr_err_ratelimited("%s: VFE pipeline violation status %d\n", __func__, violation_status); } @@ -685,6 +686,15 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, } } +void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0) +{ + if (irq_status0 & BIT(1)) + vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false; + if (irq_status0 & BIT(0)) + vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = true; +} + void msm_vfe47_reg_update(struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src) { @@ -1508,16 +1518,19 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev, pr_err("%s: no stream_clk\n", __func__); return; } - rc = msm_camera_clk_enable(&vfe_dev->pdev->dev, vfe_dev->hvx_clk_info, - vfe_dev->hvx_clk, vfe_dev->num_hvx_clk, is_stream_on); - if (rc) { - pr_err("%s: stream_clk enable failed, enable: %u\n", - __func__, - is_stream_on); - return; - } - if (is_stream_on == 1) { + if (is_stream_on) { /* Enable HVX */ + if (!vfe_dev->hvx_clk_state) { + rc = msm_camera_clk_enable(&vfe_dev->pdev->dev, + vfe_dev->hvx_clk_info, vfe_dev->hvx_clk, + vfe_dev->num_hvx_clk, is_stream_on); + if (rc) { + pr_err("%s: stream_clk enable failed\n", + __func__); + return; + } + vfe_dev->hvx_clk_state = true; + } val = msm_camera_io_r(vfe_dev->vfe_base + 0x50); val |= (1 << 3); msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50); @@ -1527,6 +1540,17 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev, msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50); } else { /* Disable HVX */ + if (!vfe_dev->hvx_clk_state) + return; + rc = msm_camera_clk_enable(&vfe_dev->pdev->dev, + vfe_dev->hvx_clk_info, vfe_dev->hvx_clk, + vfe_dev->num_hvx_clk, is_stream_on); + if (rc) { + pr_err("%s: stream_clk disable failed\n", + __func__); + return; + } + vfe_dev->hvx_clk_state = false; val = msm_camera_io_r(vfe_dev->vfe_base + 0x50); val &= 0xFFFFFFF7; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50); @@ -1895,7 +1919,7 @@ void msm_vfe47_update_ping_pong_addr( if (buf_size < 0) buf_size = 0; - paddr32_max = (paddr + buf_size) & 0xFFFFFFC0; + paddr32_max = (paddr + buf_size) & 0xFFFFFFE0; msm_camera_io_w(paddr32, vfe_base + VFE47_PING_PONG_BASE(wm_idx, pingpong_bit)); @@ -2383,18 +2407,23 @@ void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, void msm_vfe47_stats_update_ping_pong_addr( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr) + uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size) { void __iomem *vfe_base = vfe_dev->vfe_base; int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); + uint32_t paddr32_max; int stats_idx; stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); + + paddr32_max = (paddr + buf_size) & 0xFFFFFFE0; + msm_camera_io_w(paddr32_max, vfe_base + + VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status) + 0x4); } uint32_t msm_vfe47_stats_get_wm_mask( @@ -2528,6 +2557,7 @@ int msm_vfe47_get_clks(struct vfe_device *vfe_dev) vfe_dev->hvx_clk_info = &vfe_dev->vfe_clk_info[vfe_dev->num_clk-1]; vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1]; + vfe_dev->hvx_clk_state = false; } for (i = 0; i < vfe_dev->num_clk; i++) { @@ -2553,8 +2583,8 @@ void msm_vfe47_put_clks(struct vfe_device *vfe_dev) int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable) { return msm_camera_clk_enable(&vfe_dev->pdev->dev, - vfe_dev->vfe_clk_info, - vfe_dev->vfe_clk, vfe_dev->num_norm_clk, enable); + vfe_dev->vfe_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_norm_clk, enable); } int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate) @@ -2915,6 +2945,7 @@ struct msm_vfe_hardware_info vfe47_hw_info = { .process_epoch_irq = msm_vfe47_process_epoch_irq, .config_irq = msm_vfe47_config_irq, .read_irq_status = msm_vfe47_read_irq_status, + .preprocess_camif_irq = msm_isp47_preprocess_camif_irq, }, .axi_ops = { .reload_wm = msm_vfe47_axi_reload_wm, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h index 22a1a21bce9a..60afe3a80091 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014,2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,6 +42,8 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts); +void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0); void msm_vfe47_reg_update(struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src); long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev, @@ -148,7 +150,7 @@ void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, uint32_t stats_mask, uint8_t enable); void msm_vfe47_stats_update_ping_pong_addr( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, - uint32_t pingpong_status, dma_addr_t paddr); + uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size); uint32_t msm_vfe47_stats_get_wm_mask( uint32_t irq_status0, uint32_t irq_status1); uint32_t msm_vfe47_stats_get_comp_mask( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c index 5b4d6aa63055..e3d8ecb410ff 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c @@ -237,6 +237,7 @@ static int msm_vfe48_get_clks(struct vfe_device *vfe_dev) vfe_dev->hvx_clk_info = &vfe_dev->vfe_clk_info[vfe_dev->num_clk-1]; vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1]; + vfe_dev->hvx_clk_state = false; } for (i = 0; i < vfe_dev->num_clk; i++) { @@ -368,6 +369,7 @@ struct msm_vfe_hardware_info vfe48_hw_info = { .process_stats_irq = msm_isp_process_stats_irq, .process_epoch_irq = msm_vfe47_process_epoch_irq, .config_irq = msm_vfe47_config_irq, + .preprocess_camif_irq = msm_isp47_preprocess_camif_irq, }, .axi_ops = { .reload_wm = msm_vfe47_axi_reload_wm, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index ac8fea1760d1..b44b7573e0e6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -948,6 +948,8 @@ static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev, uint32_t pingpong_status = 0, pingpong_bit = 0; struct msm_isp_buffer *done_buf = NULL; int vfe_idx = -1; + /* initialize pd_buf_idx with an invalid index 0xF */ + vfe_dev->pd_buf_idx = 0xF; if (frame_src < VFE_RAW_0 || frame_src > VFE_RAW_2) return; @@ -1171,7 +1173,7 @@ void msm_isp_get_avtimer_ts( rc = avcs_core_query_timer(&avtimer_tick); if (rc < 0) { - pr_err("%s: Error: Invalid AVTimer Tick, rc=%d\n", + pr_err_ratelimited("%s: Error: Invalid AVTimer Tick, rc=%d\n", __func__, rc); /* In case of error return zero AVTimer Tick Value */ time_stamp->vt_time.tv_sec = 0; @@ -3331,6 +3333,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, int k; uint32_t wm_mask = 0; int vfe_idx; + uint32_t pingpong_bit = 0; if (!vfe_dev || !stream_info) { pr_err("%s %d failed: vfe_dev %pK stream_info %pK\n", __func__, @@ -3349,27 +3352,40 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, } frame_src = SRC_TO_INTF(stream_info->stream_src); + pingpong_status = vfe_dev->hw_info-> + vfe_ops.axi_ops.get_pingpong_status(vfe_dev); /* * If PIX stream is active then RDI path uses SOF frame ID of PIX * In case of standalone RDI streaming, SOF are used from * individual intf. */ - if (((vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id <= - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id)) || - ((!vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id <= - vfe_dev->axi_data.src_info[frame_src].frame_id)) || - stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) { - pr_debug("%s:%d invalid request_frame %d cur frame id %d pix %d\n", + /* + * If frame_id = 1 then no eof check is needed + */ + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active && + vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame == false) { + pr_debug("%s:%d invalid time to request frame %d\n", + __func__, __LINE__, frame_id); + goto error; + } + if ((vfe_dev->axi_data.src_info[VFE_PIX_0].active && (frame_id != + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id + vfe_dev-> + axi_data.src_info[VFE_PIX_0].sof_counter_step)) || + ((!vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id != + vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev-> + axi_data.src_info[frame_src].sof_counter_step))) { + pr_debug("%s:%d invalid frame id %d cur frame id %d pix %d\n", __func__, __LINE__, frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].active); - - rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, - user_stream_id, frame_id, buf_index, frame_src); - if (rc < 0) - pr_err("%s:%d failed: return_empty_buffer src %d\n", - __func__, __LINE__, frame_src); - return 0; + goto error; + } + if (stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) { + pr_debug("%s:%d invalid undelivered_request_cnt %d frame id %d\n", + __func__, __LINE__, + stream_info->undelivered_request_cnt, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + goto error; } if ((frame_src == VFE_PIX_0) && !stream_info->undelivered_request_cnt && MSM_VFE_STREAM_STOP_PERIOD != @@ -3391,6 +3407,25 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, } spin_lock_irqsave(&stream_info->lock, flags); + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + if (stream_info->undelivered_request_cnt == 1) { + pingpong_status = + vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status( + vfe_dev); + pingpong_bit = ((pingpong_status >> + stream_info->wm[vfe_idx][0]) & 0x1); + if (stream_info->sw_ping_pong_bit == !pingpong_bit) { + ISP_DBG("%s:Return Empty Buffer stream id 0x%X\n", + __func__, stream_info->stream_id); + rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, + user_stream_id, frame_id, buf_index, + frame_src); + spin_unlock_irqrestore(&stream_info->lock, + flags); + return 0; + } + } + queue_req = &stream_info->request_queue_cmd[stream_info->request_q_idx]; if (queue_req->cmd_used) { spin_unlock_irqrestore(&stream_info->lock, flags); @@ -3420,7 +3455,6 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, stream_info->request_q_cnt++; stream_info->undelivered_request_cnt++; - vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle[vfe_idx]; stream_cfg_cmd.frame_skip_pattern = NO_SKIP; stream_cfg_cmd.init_frame_drop = 0; @@ -3449,9 +3483,6 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, } stream_info->sw_ping_pong_bit = 0; } else if (stream_info->undelivered_request_cnt == 2) { - pingpong_status = - vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status( - vfe_dev); rc = msm_isp_cfg_ping_pong_address( stream_info, pingpong_status); if (rc) { @@ -3477,6 +3508,14 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, spin_unlock_irqrestore(&stream_info->lock, flags); return rc; +error: + rc = msm_isp_return_empty_buffer(vfe_dev, stream_info, + user_stream_id, frame_id, buf_index, frame_src); + if (rc < 0) + pr_err("%s:%d failed: return_empty_buffer src %d\n", + __func__, __LINE__, frame_src); + return 0; + } static int msm_isp_add_buf_queue(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index 66292acb5ef3..f2cf4d477b3f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -23,7 +23,8 @@ static inline void msm_isp_stats_cfg_wm_scratch(struct vfe_device *vfe_dev, { vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( vfe_dev, stream_info, - pingpong_status, vfe_dev->buf_mgr->scratch_buf_stats_addr); + pingpong_status, vfe_dev->buf_mgr->scratch_buf_stats_addr, + SZ_32M); } static inline void msm_isp_stats_cfg_stream_scratch( @@ -123,7 +124,8 @@ static int msm_isp_stats_cfg_ping_pong_address( vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( vfe_dev, stream_info, pingpong_status, buf->mapped_info[0].paddr + - stream_info->buffer_offset[k]); + stream_info->buffer_offset[k], + buf->mapped_info[0].len); } stream_info->buf[pingpong_bit] = buf; buf->pingpong_bit = pingpong_bit; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 2927fb851a06..f4e81c02208c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -2092,7 +2092,10 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data) __func__, vfe_dev->pdev->id); return IRQ_HANDLED; } - + if (vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq) { + vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq( + vfe_dev, irq_status0); + } if (msm_isp_process_overflow_irq(vfe_dev, &irq_status0, &irq_status1, 0)) { /* if overflow initiated no need to handle the interrupts */ diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 9d52107c9993..41d8ef577a27 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -73,7 +73,7 @@ static void msm_ispif_io_dump_reg(struct ispif_device *ispif) static inline int msm_ispif_is_intf_valid(uint32_t csid_version, - uint8_t intf_type) + enum msm_ispif_vfe_intf intf_type) { return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) || (intf_type >= VFE_MAX)) ? false : true; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index c945e4c2fbd4..ec30a004f319 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -200,22 +200,30 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev) static int smsusb_sendrequest(void *context, void *buffer, size_t size) { struct smsusb_device_t *dev = (struct smsusb_device_t *) context; - struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; - int dummy; + struct sms_msg_hdr *phdr; + int dummy, ret; if (dev->state != SMSUSB_ACTIVE) { pr_debug("Device not active yet\n"); return -ENOENT; } + phdr = kmalloc(size, GFP_KERNEL); + if (!phdr) + return -ENOMEM; + memcpy(phdr, buffer, size); + pr_debug("sending %s(%d) size: %d\n", smscore_translate_msg(phdr->msg_type), phdr->msg_type, phdr->msg_length); smsendian_handle_tx_message((struct sms_msg_data *) phdr); - smsendian_handle_message_header((struct sms_msg_hdr *)buffer); - return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), - buffer, size, &dummy, 1000); + smsendian_handle_message_header((struct sms_msg_hdr *)phdr); + ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), + phdr, size, &dummy, 1000); + + kfree(phdr); + return ret; } static char *smsusb1_fw_lkup[] = { diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cfb868a48b5f..ff6feff21e94 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -416,7 +416,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, nextbuf = NULL; spin_unlock_irqrestore(&queue->irqlock, flags); - buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; + buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused); vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 78f03fc75761..9855bee67627 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -2333,7 +2333,13 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) ret); goto loadapp_err; } - + if (load_img_req.mdt_len > len || load_img_req.img_len > len) { + pr_err("ion len %zu is smaller than mdt_len %u or img_len %u\n", + len, load_img_req.mdt_len, + load_img_req.img_len); + ret = -EINVAL; + goto loadapp_err; + } /* Populate the structure for sending scm call to load image */ if (qseecom.qsee_version < QSEE_VERSION_40) { load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND; @@ -5149,6 +5155,12 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, ret); return ret; } + if (load_img_req.mdt_len > len || load_img_req.img_len > len) { + pr_err("ion len %zu is smaller than mdt_len %u or img_len %u\n", + len, load_img_req.mdt_len, + load_img_req.img_len); + return ret; + } /* Populate the structure for sending scm call to load image */ if (qseecom.qsee_version < QSEE_VERSION_40) { load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4567b7526469..542f1733d0dd 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2032,10 +2032,10 @@ reinit: err = mmc_select_hs400(card); if (err) goto free_card; - } else if (mmc_card_hs(card)) { + } else { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); - if (!IS_ERR_VALUE(err)) { + if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) { err = mmc_select_hs_ddr(card); if (err) goto free_card; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 7274a6d2cce0..b696f54286da 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -3304,6 +3304,21 @@ static void sdhci_msm_cmdq_dump_debug_ram(struct sdhci_host *host) pr_err("-------------------------\n"); } +static void sdhci_msm_cache_debug_data(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct sdhci_msm_debug_data *cached_data = &msm_host->cached_data; + + memcpy(&cached_data->copy_mmc, msm_host->mmc, + sizeof(struct mmc_host)); + if (msm_host->mmc->card) + memcpy(&cached_data->copy_card, msm_host->mmc->card, + sizeof(struct mmc_card)); + memcpy(&cached_data->copy_host, host, + sizeof(struct sdhci_host)); +} + void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -3316,6 +3331,7 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) u32 debug_reg[MAX_TEST_BUS] = {0}; u32 sts = 0; + sdhci_msm_cache_debug_data(host); pr_info("----------- VENDOR REGISTER DUMP -----------\n"); if (host->cq_host) sdhci_msm_cmdq_dump_debug_ram(host); diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index c26636198a22..2e4f2179378e 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -171,6 +171,12 @@ struct sdhci_msm_ice_data { int state; }; +struct sdhci_msm_debug_data { + struct mmc_host copy_mmc; + struct mmc_card copy_card; + struct sdhci_host copy_host; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -186,6 +192,7 @@ struct sdhci_msm_host { atomic_t clks_on; /* Set if clocks are enabled */ struct sdhci_msm_pltfm_data *pdata; struct mmc_host *mmc; + struct sdhci_msm_debug_data cached_data; struct sdhci_pltfm_data sdhci_msm_pdata; u32 curr_pwr_state; u32 curr_io_level; diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index f9fa3fad728e..2051f28ddac6 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -139,15 +139,13 @@ static int __init init_msp_flash(void) } msp_maps[i].bankwidth = 1; - msp_maps[i].name = kmalloc(7, GFP_KERNEL); + msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL); if (!msp_maps[i].name) { iounmap(msp_maps[i].virt); kfree(msp_parts[i]); goto cleanup_loop; } - msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7); - for (j = 0; j < pcnt; j++) { part_name[5] = '0' + i; part_name[7] = '0' + j; diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index a731720f1d13..449b2a47f9a8 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -954,8 +954,8 @@ static int usb_8dev_probe(struct usb_interface *intf, for (i = 0; i < MAX_TX_URBS; i++) priv->tx_contexts[i].echo_index = MAX_TX_URBS; - priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg), - GFP_KERNEL); + priv->cmd_msg_buffer = devm_kzalloc(&intf->dev, sizeof(struct usb_8dev_cmd_msg), + GFP_KERNEL); if (!priv->cmd_msg_buffer) goto cleanup_candev; @@ -969,7 +969,7 @@ static int usb_8dev_probe(struct usb_interface *intf, if (err) { netdev_err(netdev, "couldn't register CAN device: %d\n", err); - goto cleanup_cmd_msg_buffer; + goto cleanup_candev; } err = usb_8dev_cmd_version(priv, &version); @@ -990,9 +990,6 @@ static int usb_8dev_probe(struct usb_interface *intf, cleanup_unregister_candev: unregister_netdev(priv->netdev); -cleanup_cmd_msg_buffer: - kfree(priv->cmd_msg_buffer); - cleanup_candev: free_candev(netdev); diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 25aba9886990..0e67145bc418 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -993,7 +993,7 @@ static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu, txq_pcpu->buffs + txq_pcpu->txq_put_index; tx_buf->skb = skb; tx_buf->size = tx_desc->data_size; - tx_buf->phys = tx_desc->buf_phys_addr; + tx_buf->phys = tx_desc->buf_phys_addr + tx_desc->packet_offset; txq_pcpu->txq_put_index++; if (txq_pcpu->txq_put_index == txq_pcpu->size) txq_pcpu->txq_put_index = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index bbff8ec6713e..28a4b34310b2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -502,8 +502,11 @@ void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv) return; for (ring = 0; ring < priv->rx_ring_num; ring++) { - if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) + if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) { + local_bh_disable(); napi_reschedule(&priv->rx_cq[ring]->napi); + local_bh_enable(); + } } } diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index d52ea3008946..7e8bce46e6b4 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -1237,7 +1237,7 @@ int cpmac_init(void) goto fail_alloc; } -#warning FIXME: unhardcode gpio&reset bits + /* FIXME: unhardcode gpio&reset bits */ ar7_gpio_disable(26); ar7_gpio_disable(27); ar7_device_reset(AR7_RESET_BIT_CPMAC_LO); diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 860d4aed8274..43617ded3773 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -30,7 +30,7 @@ static int numlbs = 2; static LIST_HEAD(fakelb_phys); -static DEFINE_SPINLOCK(fakelb_phys_lock); +static DEFINE_MUTEX(fakelb_phys_lock); static LIST_HEAD(fakelb_ifup_phys); static DEFINE_RWLOCK(fakelb_ifup_phys_lock); @@ -180,9 +180,9 @@ static int fakelb_add_one(struct device *dev) if (err) goto err_reg; - spin_lock(&fakelb_phys_lock); + mutex_lock(&fakelb_phys_lock); list_add_tail(&phy->list, &fakelb_phys); - spin_unlock(&fakelb_phys_lock); + mutex_unlock(&fakelb_phys_lock); return 0; @@ -214,10 +214,10 @@ static int fakelb_probe(struct platform_device *pdev) return 0; err_slave: - spin_lock(&fakelb_phys_lock); + mutex_lock(&fakelb_phys_lock); list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); - spin_unlock(&fakelb_phys_lock); + mutex_unlock(&fakelb_phys_lock); return err; } @@ -225,10 +225,10 @@ static int fakelb_remove(struct platform_device *pdev) { struct fakelb_phy *phy, *tmp; - spin_lock(&fakelb_phys_lock); + mutex_lock(&fakelb_phys_lock); list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); - spin_unlock(&fakelb_phys_lock); + mutex_unlock(&fakelb_phys_lock); return 0; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index dc7d970bd1c0..effcdbfb06e9 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -164,6 +164,7 @@ static void loopback_setup(struct net_device *dev) { dev->mtu = 64 * 1024; dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->min_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 159a68782bec..79de9608ac48 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -725,7 +725,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, ssize_t n; if (q->flags & IFF_VNET_HDR) { - vnet_hdr_len = q->vnet_hdr_sz; + vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); err = -EINVAL; if (len < vnet_hdr_len) @@ -865,7 +865,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if (q->flags & IFF_VNET_HDR) { struct virtio_net_hdr vnet_hdr; - vnet_hdr_len = q->vnet_hdr_sz; + vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); if (iov_iter_count(iter) < vnet_hdr_len) return -EINVAL; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dd7b7d64c90a..a444294fb555 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1105,9 +1105,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } if (tun->flags & IFF_VNET_HDR) { - if (len < tun->vnet_hdr_sz) + int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); + + if (len < vnet_hdr_sz) return -EINVAL; - len -= tun->vnet_hdr_sz; + len -= vnet_hdr_sz; n = copy_from_iter(&gso, sizeof(gso), from); if (n != sizeof(gso)) @@ -1119,7 +1121,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, if (tun16_to_cpu(tun, gso.hdr_len) > len) return -EINVAL; - iov_iter_advance(from, tun->vnet_hdr_sz - sizeof(gso)); + iov_iter_advance(from, vnet_hdr_sz - sizeof(gso)); } if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) { @@ -1302,7 +1304,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, vlan_hlen = VLAN_HLEN; if (tun->flags & IFF_VNET_HDR) - vnet_hdr_sz = tun->vnet_hdr_sz; + vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); total = skb->len + vlan_hlen + vnet_hdr_sz; diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 25b23bf2c8e6..5fe8bc184868 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -26,6 +26,7 @@ ath10k_pci-y += pci.o \ ce.o obj-$(CONFIG_ATH10K_TARGET_SNOC) += ath10k_snoc.o ath10k_snoc-y += snoc.o \ + qmi.o \ ce.o ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index b8a3a1ecabaa..9cda1303c9e1 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -455,6 +455,9 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, u32 desc_flags = 0; int ret = 0; + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + return -ESHUTDOWN; + if (nbytes > ce_state->src_sz_max) ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", __func__, nbytes, ce_state->src_sz_max); @@ -942,6 +945,9 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) struct ath10k_ce_pipe *ce_state; struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + return; + if (ar->target_version == ATH10K_HW_WCN3990) intr_summary = 0xFFF; else diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index d37ed66d767b..9acaffa51516 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1536,7 +1536,6 @@ static void ath10k_core_restart(struct work_struct *work) struct ath10k *ar = container_of(work, struct ath10k, restart_work); set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); - ath10k_gen_set_base_mac_addr(ar, ar->base_mac_addr); /* Place a barrier to make sure the compiler doesn't reorder * CRASH_FLUSH and calling other functions. @@ -2390,6 +2389,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, mutex_init(&ar->conf_mutex); spin_lock_init(&ar->data_lock); spin_lock_init(&ar->txqs_lock); + spin_lock_init(&ar->datapath_rx_stat_lock); INIT_LIST_HEAD(&ar->txqs); INIT_LIST_HEAD(&ar->peers); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index a20ac680cfb9..01d5ecc4f6b8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -70,6 +70,20 @@ #define ATH10K_NAPI_BUDGET 64 #define ATH10K_NAPI_QUOTA_LIMIT 60 +#define ATH10K_RX_MCS_MIN 0 +#define ATH10K_RX_HT_MCS_MAX 32 +#define ATH10K_RX_VHT_RATEIDX_MAX 9 +#define ATH10K_RX_VHT_MCS_MAX 20 /* For 2x2 */ +#define ATH10K_RX_NSS_MIN 0 +#define ATH10K_RX_NSS_MAX 5 + +enum ath10k_datapath_rx_band { + ATH10K_BAND_MIN, + ATH10K_BAND_2GHZ = ATH10K_BAND_MIN, + ATH10K_BAND_5GHZ, + ATH10K_BAND_MAX, +}; + struct ath10k; enum ath10k_bus { @@ -703,6 +717,20 @@ struct ath10k_fw_components { struct ath10k_fw_file fw_file; }; +struct datapath_rx_stats { + u32 no_of_packets; + u32 short_gi_pkts; + u32 ht_rate_indx[ATH10K_RX_HT_MCS_MAX + 1]; + u32 vht_rate_indx[ATH10K_RX_VHT_MCS_MAX + 1]; + u32 ht_rate_packets; + u32 vht_rate_packets; + u32 legacy_pkt; + u32 nss[ATH10K_RX_NSS_MAX + 1]; + u32 num_pkts_40Mhz; + u32 num_pkts_80Mhz; + u32 band[ATH10K_BAND_MAX + 1]; +}; + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -900,7 +928,10 @@ struct ath10k { enum ath10k_spectral_mode mode; struct ath10k_spec_scan config; } spectral; + struct datapath_rx_stats *rx_stats; #endif + /* prevent concurrency histogram for receiving data packet */ + spinlock_t datapath_rx_stat_lock; struct { /* protected by conf_mutex */ diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8d97822cbbde..ec8063e7986a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -537,6 +537,230 @@ static const struct file_operations fops_fw_stats = { .llseek = default_llseek, }; +static inline int is_vht_rate_valid(u32 rate_indx) +{ + if ((rate_indx >= ATH10K_RX_MCS_MIN) && + (rate_indx <= ATH10K_RX_VHT_RATEIDX_MAX)) + return 1; + else + return 0; +} + +void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status) +{ + struct datapath_rx_stats *stat_cnt = ar->rx_stats; + + spin_lock_bh(&ar->datapath_rx_stat_lock); + + stat_cnt->no_of_packets += 1; + if (!(stat_cnt->no_of_packets)) { + memset(stat_cnt, 0, sizeof(*stat_cnt)); + stat_cnt->no_of_packets += 1; + } + + if (status->flag & RX_FLAG_SHORT_GI) + stat_cnt->short_gi_pkts += 1; + + if ((status->vht_nss >= ATH10K_RX_NSS_MIN) && + (status->vht_nss < ATH10K_RX_NSS_MAX)) { + stat_cnt->nss[status->vht_nss] += 1; + if (status->flag & RX_FLAG_VHT) { + stat_cnt->vht_rate_packets += 1; + if (is_vht_rate_valid(status->rate_idx)) { + stat_cnt->vht_rate_indx[((status->vht_nss - 1) * + 10) + status->rate_idx] += 1; + } else { + /*if we get index other than (>=0 and <=9)*/ + stat_cnt->vht_rate_indx[ATH10K_RX_VHT_MCS_MAX] += 1; + } + } else if (status->flag & RX_FLAG_HT) { + stat_cnt->ht_rate_packets += 1; + if ((status->rate_idx >= ATH10K_RX_MCS_MIN) && + (status->rate_idx < ATH10K_RX_HT_MCS_MAX)) + stat_cnt->ht_rate_indx[status->rate_idx] += 1; + else { + /*if we get index other than (>=0 and <=31)*/ + stat_cnt->ht_rate_indx[ATH10K_RX_HT_MCS_MAX] += 1; + } + } else { + /* if pkt is other than HT and VHT */ + stat_cnt->legacy_pkt += 1; + } + } else { + stat_cnt->nss[ATH10K_RX_NSS_MAX] += 1; + } + + if (status->flag & RX_FLAG_40MHZ) + stat_cnt->num_pkts_40Mhz += 1; + if (status->vht_flag & RX_VHT_FLAG_80MHZ) + stat_cnt->num_pkts_80Mhz += 1; + if ((status->band >= ATH10K_BAND_MIN) && + (status->band < ATH10K_BAND_MAX)) { + stat_cnt->band[status->band] += 1; + } else { + /*if band is other than 0,1 */ + stat_cnt->band[ATH10K_BAND_MAX] += 1; + } + + spin_unlock_bh(&ar->datapath_rx_stat_lock); +} + +size_t get_datapath_stat(char *buf, struct ath10k *ar) +{ + u8 i; + struct datapath_rx_stats *stat_cnt = ar->rx_stats; + size_t j = 0; + + spin_lock(&ar->datapath_rx_stat_lock); + + j = snprintf(buf, ATH10K_DATAPATH_BUF_SIZE, "\nNo of packets: %u\t" + "No of short_gi packets: %u\n" + "\nHT Packets: %u \t VHT Packets: %u\n" + "\n40Mhz Packets: %u \t 80Mhz Packets: %u\n" + "\n2.4GHz: %u \t 5GHz: %u \t band-error: %u\n\n", + stat_cnt->no_of_packets, + stat_cnt->short_gi_pkts, + stat_cnt->ht_rate_packets, + stat_cnt->vht_rate_packets, + stat_cnt->num_pkts_40Mhz, + stat_cnt->num_pkts_80Mhz, + stat_cnt->band[ATH10K_BAND_2GHZ], + stat_cnt->band[ATH10K_BAND_5GHZ], + stat_cnt->band[ATH10K_BAND_MAX]); + + for (i = 0; i <= ATH10K_RX_NSS_MAX; i++) { + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "NSS-%u: %u\t", i, stat_cnt->nss[i]); + } + + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "\n\n----HT Rate index------\n"); + + for (i = ATH10K_RX_MCS_MIN; i < ATH10K_RX_HT_MCS_MAX; + i += 4) { + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "ht_rate_indx[%02u]: %10u\tht_rate_indx[%02u]: %10u\t" + "ht_rate_indx[%02u]: %10u\tht_rate_indx[%02u]: %10u\n", + i, stat_cnt->ht_rate_indx[i], + i + 1, stat_cnt->ht_rate_indx[i + 1], + i + 2, stat_cnt->ht_rate_indx[i + 2], + i + 3, stat_cnt->ht_rate_indx[i + 3]); + } + + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "ht_rate_indx[OOB]: %10u\n", + stat_cnt->ht_rate_indx[ATH10K_RX_HT_MCS_MAX]); + + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "\n----VHT Rate index------\n"); + + for (i = ATH10K_RX_MCS_MIN; + i <= ATH10K_RX_VHT_RATEIDX_MAX; i++) { + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "vht_rate_indx[%02u]: %10u\tvht_rate_indx[%02u]: %10u\n", + i, stat_cnt->vht_rate_indx[i], + i + 10, stat_cnt->vht_rate_indx[i + 10]); + } + + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "vht_rate_indx[%02u]: %10u\n", + i + 10, stat_cnt->vht_rate_indx[i + 10]); + + j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j), + "\nnumber of pkt other than HT and VHT(legacy) : %u\n" + "----------------------\n", + stat_cnt->legacy_pkt); + + spin_unlock(&ar->datapath_rx_stat_lock); + + return j; +} + +static int ath10k_datapath_stats_open(struct inode *inode, struct file *file) +{ + struct ath10k *ar = inode->i_private; + int ret; + + spin_lock(&ar->datapath_rx_stat_lock); + + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto err_unlock; + } + + file->private_data = ar; + + spin_unlock(&ar->datapath_rx_stat_lock); + return 0; + +err_unlock: + spin_unlock(&ar->datapath_rx_stat_lock); + return ret; +} + +static ssize_t ath10k_datapath_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + size_t buf_len; + unsigned int ret; + void *buf = NULL; + + buf = vmalloc(ATH10K_DATAPATH_BUF_SIZE); + if (!buf) + return 0; + + buf_len = get_datapath_stat(buf, ar); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, buf_len); + vfree(buf); + + return ret; +} + +static ssize_t ath10k_datapath_stats_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u32 filter; + int ret; + + if (kstrtouint_from_user(ubuf, count, 0, &filter)) + return -EINVAL; + + spin_lock(&ar->datapath_rx_stat_lock); + + if (ar->state != ATH10K_STATE_ON) { + ret = count; + goto err_unlock; + } + + if (!filter) + memset(ar->rx_stats, 0, sizeof(*ar->rx_stats)); + + ret = count; + +err_unlock: + spin_unlock(&ar->datapath_rx_stat_lock); + return ret; +} + +static int ath10k_datapath_stats_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations fops_datapath_stats = { + .open = ath10k_datapath_stats_open, + .read = ath10k_datapath_stats_read, + .write = ath10k_datapath_stats_write, + .release = ath10k_datapath_stats_release, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2401,7 +2625,11 @@ int ath10k_debug_create(struct ath10k *ar) ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); if (!ar->debug.cal_data) - return -ENOMEM; + goto err_cal_data; + + ar->rx_stats = vzalloc(sizeof(*ar->rx_stats)); + if (!ar->rx_stats) + goto err_rx_stats; INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); @@ -2409,6 +2637,13 @@ int ath10k_debug_create(struct ath10k *ar) INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd); return 0; + +err_rx_stats: + vfree(ar->debug.cal_data); + +err_cal_data: + vfree(ar->debug.fw_crash_data); + return -ENOMEM; } void ath10k_debug_destroy(struct ath10k *ar) @@ -2419,6 +2654,9 @@ void ath10k_debug_destroy(struct ath10k *ar) vfree(ar->debug.cal_data); ar->debug.cal_data = NULL; + vfree(ar->rx_stats); + ar->rx_stats = NULL; + ath10k_debug_fw_stats_reset(ar); kfree(ar->debug.tpc_stats); @@ -2441,6 +2679,9 @@ int ath10k_debug_register(struct ath10k *ar) init_completion(&ar->debug.tpc_complete); init_completion(&ar->debug.fw_stats_complete); + debugfs_create_file("datapath_rx_stats", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_datapath_stats); + debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_fw_stats); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index b1db01a167ac..f963391e3544 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -38,7 +38,7 @@ enum ath10k_debug_mask { ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_PCI_PS = 0x00004000, ATH10K_DBG_AHB = 0x00008000, - ATH10K_DBG_SNOC = 0x00009000, + ATH10K_DBG_SNOC = 0x00010000, ATH10K_DBG_ANY = 0xffffffff, }; @@ -59,6 +59,7 @@ enum ath10k_dbg_aggr_mode { /* FIXME: How to calculate the buffer size sanely? */ #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) +#define ATH10K_DATAPATH_BUF_SIZE (1024 * 1024) extern unsigned int ath10k_debug_mask; @@ -95,6 +96,8 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data); +void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status); +size_t get_datapath_stat(char *buf, struct ath10k *ar); #else static inline int ath10k_debug_start(struct ath10k *ar) { @@ -145,6 +148,16 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) return NULL; } +static inline void fill_datapath_stats(struct ath10k *ar, + struct ieee80211_rx_status *status) +{ +} + +static inline size_t get_datapath_stat(char *buf, struct ath10k *ar) +{ + return 0; +} + #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #define ath10k_debug_get_et_strings NULL diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index ddf097e3a143..437ea2c192b3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -940,7 +940,7 @@ static void ath10k_process_rx(struct ath10k *ar, status = IEEE80211_SKB_RXCB(skb); *status = *rx_status; - + fill_datapath_stats(ar, status); ath10k_dbg(ar, ATH10K_DBG_DATA, "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", skb, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 265744c75f82..35e5d980ed49 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4450,7 +4450,8 @@ static int ath10k_start(struct ieee80211_hw *hw) ar->state = ATH10K_STATE_ON; break; case ATH10K_STATE_RESTARTING: - ath10k_halt(ar); + if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + ath10k_halt(ar); ar->state = ATH10K_STATE_RESTARTED; break; case ATH10K_STATE_ON: diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c new file mode 100644 index 000000000000..7b5fc52d269a --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 <soc/qcom/subsystem_notif.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/service-notifier.h> +#include "core.h" +#include "qmi.h" +#include "snoc.h" +#include <soc/qcom/icnss.h> + +static int +ath10k_snoc_service_notifier_notify(struct notifier_block *nb, + unsigned long notification, void *data) +{ + struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, + service_notifier_nb); + enum pd_subsys_state *state = data; + struct ath10k *ar = ar_snoc->ar; + + switch (notification) { + case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service down, data: 0x%pK\n", + data); + + if (!state || *state != ROOT_PD_SHUTDOWN) + atomic_set(&ar_snoc->fw_crashed, 1); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "PD went down %d\n", + atomic_read(&ar_snoc->fw_crashed)); + break; + case SERVREG_NOTIF_SERVICE_STATE_UP_V01: + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service up\n"); + queue_work(ar->workqueue, &ar->restart_work); + break; + default: + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Service state Unknown, notification: 0x%lx\n", + notification); + return NOTIFY_DONE; + } + return NOTIFY_OK; +} + +static int ath10k_snoc_get_service_location_notify(struct notifier_block *nb, + unsigned long opcode, + void *data) +{ + struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, + get_service_nb); + struct ath10k *ar = ar_snoc->ar; + struct pd_qmi_client_data *pd = data; + int curr_state; + int ret; + int i; + struct ath10k_service_notifier_context *notifier; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Get service notify opcode: %lu\n", + opcode); + + if (opcode != LOCATOR_UP) + return NOTIFY_DONE; + + if (!pd->total_domains) { + ath10k_err(ar, "Did not find any domains\n"); + ret = -ENOENT; + goto out; + } + + notifier = kcalloc(pd->total_domains, + sizeof(struct ath10k_service_notifier_context), + GFP_KERNEL); + if (!notifier) { + ret = -ENOMEM; + goto out; + } + + ar_snoc->service_notifier_nb.notifier_call = + ath10k_snoc_service_notifier_notify; + + for (i = 0; i < pd->total_domains; i++) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "%d: domain_name: %s, instance_id: %d\n", i, + pd->domain_list[i].name, + pd->domain_list[i].instance_id); + + notifier[i].handle = + service_notif_register_notifier( + pd->domain_list[i].name, + pd->domain_list[i].instance_id, + &ar_snoc->service_notifier_nb, + &curr_state); + notifier[i].instance_id = pd->domain_list[i].instance_id; + strlcpy(notifier[i].name, pd->domain_list[i].name, + QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1); + + if (IS_ERR(notifier[i].handle)) { + ath10k_err(ar, "%d: Unable to register notifier for %s(0x%x)\n", + i, pd->domain_list->name, + pd->domain_list->instance_id); + ret = PTR_ERR(notifier[i].handle); + goto free_handle; + } + } + + ar_snoc->service_notifier = notifier; + ar_snoc->total_domains = pd->total_domains; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "PD restart enabled\n"); + + return NOTIFY_OK; + +free_handle: + for (i = 0; i < pd->total_domains; i++) { + if (notifier[i].handle) { + service_notif_unregister_notifier( + notifier[i].handle, + &ar_snoc->service_notifier_nb); + } + } + kfree(notifier); + +out: + ath10k_err(ar, "PD restart not enabled: %d\n", ret); + + return NOTIFY_OK; +} + +int ath10k_snoc_pd_restart_enable(struct ath10k *ar) +{ + int ret; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Get service location\n"); + + ar_snoc->get_service_nb.notifier_call = + ath10k_snoc_get_service_location_notify; + ret = get_service_location(ATH10K_SERVICE_LOCATION_CLIENT_NAME, + ATH10K_WLAN_SERVICE_NAME, + &ar_snoc->get_service_nb); + if (ret) { + ath10k_err(ar, "Get service location failed: %d\n", ret); + goto out; + } + + return 0; +out: + ath10k_err(ar, "PD restart not enabled: %d\n", ret); + return ret; +} + +int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar) +{ + int i; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + for (i = 0; i < ar_snoc->total_domains; i++) { + if (ar_snoc->service_notifier[i].handle) + service_notif_unregister_notifier( + ar_snoc->service_notifier[i].handle, + &ar_snoc->service_notifier_nb); + } + + kfree(ar_snoc->service_notifier); + + ar_snoc->service_notifier = NULL; + + return 0; +} + +static int ath10k_snoc_modem_notifier_nb(struct notifier_block *nb, + unsigned long code, + void *data) +{ + struct notif_data *notif = data; + struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, + modem_ssr_nb); + struct ath10k *ar = ar_snoc->ar; + + if (code != SUBSYS_BEFORE_SHUTDOWN) + return NOTIFY_OK; + + if (notif->crashed) + atomic_set(&ar_snoc->fw_crashed, 1); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Modem went down %d\n", + atomic_read(&ar_snoc->fw_crashed)); + if (notif->crashed) + queue_work(ar->workqueue, &ar->restart_work); + + return NOTIFY_OK; +} + +int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar) +{ + int ret = 0; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + ar_snoc->modem_ssr_nb.notifier_call = ath10k_snoc_modem_notifier_nb; + + ar_snoc->modem_notify_handler = + subsys_notif_register_notifier("modem", &ar_snoc->modem_ssr_nb); + + if (IS_ERR(ar_snoc->modem_notify_handler)) { + ret = PTR_ERR(ar_snoc->modem_notify_handler); + ath10k_err(ar, "Modem register notifier failed: %d\n", ret); + } + + return ret; +} + +int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + subsys_notif_unregister_notifier(ar_snoc->modem_notify_handler, + &ar_snoc->modem_ssr_nb); + ar_snoc->modem_notify_handler = NULL; + + return 0; +} + diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h new file mode 100644 index 000000000000..f8ba3288753b --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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. + */ +#ifndef _QMI_H_ +#define _QMI_H_ +int ath10k_snoc_pd_restart_enable(struct ath10k *ar); +int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar); +int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar); +int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar); + +#endif diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index dc5f6fdaa9dc..89042dcf70a0 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -24,6 +24,7 @@ #include "htc.h" #include "ce.h" #include "snoc.h" +#include "qmi.h" #include <soc/qcom/icnss.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -413,6 +414,20 @@ static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = { { 11, WCN3990_DST_WR_INDEX_OFFSET}, }; +static bool ath10k_snoc_has_fw_crashed(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + return atomic_read(&ar_snoc->fw_crashed); +} + +static void ath10k_snoc_fw_crashed_clear(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + atomic_set(&ar_snoc->fw_crashed, 0); +} + void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -655,6 +670,9 @@ static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id, "snoc tx item %d paddr %pad len %d n_items %d\n", i, &items[i].paddr, items[i].len, n_items); + if (ath10k_snoc_has_fw_crashed(ar)) + return -EINVAL; + err = ath10k_ce_send_nolock(ce_pipe, items[i].transfer_context, items[i].paddr, @@ -867,11 +885,17 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar) { if (!ar) return; - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); - ath10k_snoc_irq_disable(ar); + if (ath10k_snoc_has_fw_crashed(ar) || + test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { + ath10k_snoc_free_irq(ar); + } else { + ath10k_snoc_irq_disable(ar); + } + ath10k_snoc_flush(ar); napi_synchronize(&ar->napi); napi_disable(&ar->napi); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); } static int ath10k_snoc_alloc_pipes(struct ath10k *ar) @@ -1087,9 +1111,14 @@ static int ath10k_snoc_bus_configure(struct ath10k *ar) static int ath10k_snoc_hif_start(struct ath10k *ar) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); + if (ath10k_snoc_has_fw_crashed(ar)) { + ath10k_snoc_request_irq(ar); + ath10k_snoc_fw_crashed_clear(ar); + } ath10k_snoc_irq_enable(ar); ath10k_snoc_rx_post(ar); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); return 0; } @@ -1110,7 +1139,8 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n", __func__, ar->state); - if (ar->state == ATH10K_STATE_ON) { + if (ar->state == ATH10K_STATE_ON || + test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { ret = ath10k_snoc_bus_configure(ar); if (ret) ath10k_err(ar, "failed to configure bus: %d\n", ret); @@ -1133,6 +1163,10 @@ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) struct ath10k *ar = container_of(ctx, struct ath10k, napi); int done = 0; + if (ath10k_snoc_has_fw_crashed(ar)) { + napi_complete(ctx); + return done; + } ath10k_ce_per_engine_service_any(ar); done = ath10k_htt_txrx_compl_task(ar, budget); @@ -1254,6 +1288,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_free_irq; } + + ath10k_snoc_modem_ssr_register_notifier(ar); + ath10k_snoc_pd_restart_enable(ar); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 probed\n", __func__); return 0; @@ -1282,6 +1320,8 @@ static int ath10k_snoc_remove(struct platform_device *pdev) return -EINVAL; ath10k_core_unregister(ar); + ath10k_snoc_pdr_unregister_notifier(ar); + ath10k_snoc_modem_ssr_unregister_notifier(ar); ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); ath10k_snoc_free_pipes(ar); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 0a5f5bff37ec..c62519b2a340 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -16,8 +16,11 @@ #include "hw.h" #include "ce.h" #include "pci.h" +#include <soc/qcom/service-locator.h> #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 +#define ATH10K_SERVICE_LOCATION_CLIENT_NAME "ATH10K-WLAN" +#define ATH10K_WLAN_SERVICE_NAME "wlan/fw" /* struct snoc_state: SNOC target state * @pipe_cfg_addr: pipe configuration address @@ -88,6 +91,17 @@ struct ath10k_target_info { u32 soc_version; }; +/* struct ath10k_service_notifier_context: service notification context + * @handle: notifier handle + * @instance_id: domain instance id + * @name: domain name + */ +struct ath10k_service_notifier_context { + void *handle; + u32 instance_id; + char name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; +}; + /* struct ath10k_snoc: SNOC info struct * @dev: device structure * @ar:ath10k base structure @@ -101,6 +115,13 @@ struct ath10k_target_info { * @rx_post_retry: rx buffer post processing timer * @vaddr_rri_on_ddr: virtual address for RRI * @is_driver_probed: flag to indicate driver state + * @modem_ssr_nb: notifier callback for modem notification + * @modem_notify_handler: modem notification handler + * @service_notifier: notifier context for service notification + * @service_notifier_nb: notifier callback for service notification + * @total_domains: no of service domains + * @get_service_nb: notifier callback for service discovery + * @fw_crashed: fw state flag */ struct ath10k_snoc { struct bus_opaque opaque_ctx; @@ -115,6 +136,13 @@ struct ath10k_snoc { u32 ce_irqs[CE_COUNT_MAX]; u32 *vaddr_rri_on_ddr; bool is_driver_probed; + struct notifier_block modem_ssr_nb; + void *modem_notify_handler; + struct ath10k_service_notifier_context *service_notifier; + struct notifier_block service_notifier_nb; + int total_domains; + struct notifier_block get_service_nb; + atomic_t fw_crashed; }; /* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration @@ -171,6 +199,11 @@ struct ath10k_wlan_enable_cfg { struct ath10k_shadow_reg_cfg *shadow_reg_cfg; }; +struct ath10k_event_pd_down_data { + bool crashed; + bool fw_rejuvenate; +}; + /* enum ath10k_driver_mode: ath10k driver mode * @ATH10K_MISSION: mission mode * @ATH10K_FTM: ftm mode diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 3fef967ca1ad..75f2528b8b84 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -553,7 +553,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_tlv_event_tx_pause(ar, skb); break; default: - ath10k_warn(ar, "Unknown eventid: %d\n", id); + ath10k_dbg(ar, ATH10K_DBG_WMI, "Unknown eventid: %d\n", id); break; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4dd60b74853d..cbbba8d79e6b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1799,6 +1799,9 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) { int ret = -EOPNOTSUPP; + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + return -ESHUTDOWN; + might_sleep(); if (cmd_id == WMI_CMD_UNSUPPORTED) { diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index dc44cfef7517..16e052d02c94 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -502,8 +502,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; return -EOPNOTSUPP; default: - WARN_ON(1); - return -EINVAL; + return -EOPNOTSUPP; } mutex_lock(&ah->lock); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 694ca2e680e5..74670e08e6da 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -73,13 +73,13 @@ #define AR9300_OTP_BASE \ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000) #define AR9300_OTP_STATUS \ - ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18) + ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x31018 : 0x15f18) #define AR9300_OTP_STATUS_TYPE 0x7 #define AR9300_OTP_STATUS_VALID 0x4 #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 #define AR9300_OTP_STATUS_SM_BUSY 0x1 #define AR9300_OTP_READ_DATA \ - ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c) + ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3101c : 0x15f1c) enum targetPowerHTRates { HT_TARGET_RATE_0_8_16, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b42f4a963ef4..a660e40f2df1 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -959,6 +959,7 @@ struct ath_softc { struct survey_info *cur_survey; struct survey_info survey[ATH9K_NUM_CHANNELS]; + spinlock_t intr_lock; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; struct ath_hw *sc_ah; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index bc70ce62bc03..0f5672f5c9ba 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -619,6 +619,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, common->bt_ant_diversity = 1; spin_lock_init(&common->cc_lock); + spin_lock_init(&sc->intr_lock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); spin_lock_init(&sc->chan_lock); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index bba85d1a6cd1..d937c39b3a0b 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -805,21 +805,12 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable_interrupts); -void ath9k_hw_enable_interrupts(struct ath_hw *ah) +static void __ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); u32 sync_default = AR_INTR_SYNC_DEFAULT; u32 async_mask; - if (!(ah->imask & ATH9K_INT_GLOBAL)) - return; - - if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { - ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", - atomic_read(&ah->intr_ref_cnt)); - return; - } - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; @@ -841,6 +832,39 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); } + +void ath9k_hw_resume_interrupts(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->imask & ATH9K_INT_GLOBAL)) + return; + + if (atomic_read(&ah->intr_ref_cnt) != 0) { + ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", + atomic_read(&ah->intr_ref_cnt)); + return; + } + + __ath9k_hw_enable_interrupts(ah); +} +EXPORT_SYMBOL(ath9k_hw_resume_interrupts); + +void ath9k_hw_enable_interrupts(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->imask & ATH9K_INT_GLOBAL)) + return; + + if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { + ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", + atomic_read(&ah->intr_ref_cnt)); + return; + } + + __ath9k_hw_enable_interrupts(ah); +} EXPORT_SYMBOL(ath9k_hw_enable_interrupts); void ath9k_hw_set_interrupts(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7fbf7f965f61..1b63d26f30ce 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -748,6 +748,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah); void ath9k_hw_enable_interrupts(struct ath_hw *ah); void ath9k_hw_disable_interrupts(struct ath_hw *ah); void ath9k_hw_kill_interrupts(struct ath_hw *ah); +void ath9k_hw_resume_interrupts(struct ath_hw *ah); void ar9002_hw_attach_mac_ops(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7be31f27266c..3abc64574116 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -373,21 +373,20 @@ void ath9k_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); enum ath_reset_type type; unsigned long flags; - u32 status = sc->intrstatus; + u32 status; u32 rxmask; + spin_lock_irqsave(&sc->intr_lock, flags); + status = sc->intrstatus; + sc->intrstatus = 0; + spin_unlock_irqrestore(&sc->intr_lock, flags); + ath9k_ps_wakeup(sc); spin_lock(&sc->sc_pcu_lock); if (status & ATH9K_INT_FATAL) { type = RESET_TYPE_FATAL_INT; ath9k_queue_reset(sc, type); - - /* - * Increment the ref. counter here so that - * interrupts are enabled in the reset routine. - */ - atomic_inc(&ah->intr_ref_cnt); ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); goto out; } @@ -403,11 +402,6 @@ void ath9k_tasklet(unsigned long data) type = RESET_TYPE_BB_WATCHDOG; ath9k_queue_reset(sc, type); - /* - * Increment the ref. counter here so that - * interrupts are enabled in the reset routine. - */ - atomic_inc(&ah->intr_ref_cnt); ath_dbg(common, RESET, "BB_WATCHDOG: Skipping interrupts\n"); goto out; @@ -420,7 +414,6 @@ void ath9k_tasklet(unsigned long data) if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) { type = RESET_TYPE_TX_GTT; ath9k_queue_reset(sc, type); - atomic_inc(&ah->intr_ref_cnt); ath_dbg(common, RESET, "GTT: Skipping interrupts\n"); goto out; @@ -477,7 +470,7 @@ void ath9k_tasklet(unsigned long data) ath9k_btcoex_handle_interrupt(sc, status); /* re-enable hardware interrupt */ - ath9k_hw_enable_interrupts(ah); + ath9k_hw_resume_interrupts(ah); out: spin_unlock(&sc->sc_pcu_lock); ath9k_ps_restore(sc); @@ -541,7 +534,9 @@ irqreturn_t ath_isr(int irq, void *dev) return IRQ_NONE; /* Cache the status */ - sc->intrstatus = status; + spin_lock(&sc->intr_lock); + sc->intrstatus |= status; + spin_unlock(&sc->intr_lock); if (status & SCHED_INTR) sched = true; @@ -587,7 +582,7 @@ chip_reset: if (sched) { /* turn off every interrupt */ - ath9k_hw_disable_interrupts(ah); + ath9k_hw_kill_interrupts(ah); tasklet_schedule(&sc->intr_tq); } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 5ef4ca0adb4b..958c96b75fbb 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -997,6 +997,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + if (wil->tt_data_set) + wmi_set_tt_cfg(wil, &wil->tt_data); + wil_collect_fw_info(wil); if (wil->platform_ops.notify) { diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c index 0faa26ca41c9..a3689738a070 100644 --- a/drivers/net/wireless/ath/wil6210/sysfs.c +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -94,8 +94,119 @@ static DEVICE_ATTR(ftm_txrx_offset, 0644, wil_ftm_txrx_offset_sysfs_show, wil_ftm_txrx_offset_sysfs_store); +static ssize_t +wil_tt_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + ssize_t len; + struct wmi_tt_data tt_data; + int i, rc; + + rc = wmi_get_tt_cfg(wil, &tt_data); + if (rc) + return rc; + + len = snprintf(buf, PAGE_SIZE, " high max critical\n"); + + len += snprintf(buf + len, PAGE_SIZE - len, "bb: "); + if (tt_data.bb_enabled) + for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) + len += snprintf(buf + len, PAGE_SIZE - len, + "%03d-%03d ", + tt_data.bb_zones[i].temperature_high, + tt_data.bb_zones[i].temperature_low); + else + len += snprintf(buf + len, PAGE_SIZE - len, "* disabled *"); + len += snprintf(buf + len, PAGE_SIZE - len, "\nrf: "); + if (tt_data.rf_enabled) + for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) + len += snprintf(buf + len, PAGE_SIZE - len, + "%03d-%03d ", + tt_data.rf_zones[i].temperature_high, + tt_data.rf_zones[i].temperature_low); + else + len += snprintf(buf + len, PAGE_SIZE - len, "* disabled *"); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + + return len; +} + +static ssize_t +wil_tt_sysfs_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + int i, rc = -EINVAL; + char *token, *dupbuf, *tmp; + struct wmi_tt_data tt_data = { + .bb_enabled = 0, + .rf_enabled = 0, + }; + + tmp = kmemdup(buf, count + 1, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + tmp[count] = '\0'; + dupbuf = tmp; + + /* Format for writing is 12 unsigned bytes separated by spaces: + * <bb_z1_h> <bb_z1_l> <bb_z2_h> <bb_z2_l> <bb_z3_h> <bb_z3_l> \ + * <rf_z1_h> <rf_z1_l> <rf_z2_h> <rf_z2_l> <rf_z3_h> <rf_z3_l> + * To disable thermal throttling for bb or for rf, use 0 for all + * its six set points. + */ + + /* bb */ + for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) { + token = strsep(&dupbuf, " "); + if (!token) + goto out; + if (kstrtou8(token, 0, &tt_data.bb_zones[i].temperature_high)) + goto out; + token = strsep(&dupbuf, " "); + if (!token) + goto out; + if (kstrtou8(token, 0, &tt_data.bb_zones[i].temperature_low)) + goto out; + + if (tt_data.bb_zones[i].temperature_high > 0 || + tt_data.bb_zones[i].temperature_low > 0) + tt_data.bb_enabled = 1; + } + /* rf */ + for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) { + token = strsep(&dupbuf, " "); + if (!token) + goto out; + if (kstrtou8(token, 0, &tt_data.rf_zones[i].temperature_high)) + goto out; + token = strsep(&dupbuf, " "); + if (!token) + goto out; + if (kstrtou8(token, 0, &tt_data.rf_zones[i].temperature_low)) + goto out; + + if (tt_data.rf_zones[i].temperature_high > 0 || + tt_data.rf_zones[i].temperature_low > 0) + tt_data.rf_enabled = 1; + } + + rc = wmi_set_tt_cfg(wil, &tt_data); + if (rc) + goto out; + + rc = count; +out: + kfree(tmp); + return rc; +} + +static DEVICE_ATTR(thermal_throttling, 0644, + wil_tt_sysfs_show, wil_tt_sysfs_store); + static struct attribute *wil6210_sysfs_entries[] = { &dev_attr_ftm_txrx_offset.attr, + &dev_attr_thermal_throttling.attr, NULL }; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 5dcb723f4cb9..f64323b03a3b 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -696,6 +696,8 @@ struct wil6210_priv { struct wil_halp halp; struct wil_ftm_priv ftm; + bool tt_data_set; + struct wmi_tt_data tt_data; #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP @@ -854,6 +856,8 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short); int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short); int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid); +int wmi_set_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data); +int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data); int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index bccd27dcb42b..6a6ba02beba0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1763,6 +1763,67 @@ int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid) return rc; } +int wmi_set_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data) +{ + int rc; + struct wmi_set_thermal_throttling_cfg_cmd cmd = { + .tt_data = *tt_data, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_set_thermal_throttling_cfg_event evt; + } __packed reply; + + if (!test_bit(WMI_FW_CAPABILITY_THERMAL_THROTTLING, + wil->fw_capabilities)) + return -EOPNOTSUPP; + + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_SET_THERMAL_THROTTLING_CFG_CMDID, &cmd, + sizeof(cmd), WMI_SET_THERMAL_THROTTLING_CFG_EVENTID, + &reply, sizeof(reply), 100); + if (rc) { + wil_err(wil, "failed to set thermal throttling\n"); + return rc; + } + if (reply.evt.status) { + wil_err(wil, "set thermal throttling failed, error %d\n", + reply.evt.status); + return -EIO; + } + + wil->tt_data = *tt_data; + wil->tt_data_set = true; + + return 0; +} + +int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data) +{ + int rc; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_get_thermal_throttling_cfg_event evt; + } __packed reply; + + if (!test_bit(WMI_FW_CAPABILITY_THERMAL_THROTTLING, + wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = wmi_call(wil, WMI_GET_THERMAL_THROTTLING_CFG_CMDID, NULL, 0, + WMI_GET_THERMAL_THROTTLING_CFG_EVENTID, &reply, + sizeof(reply), 100); + if (rc) { + wil_err(wil, "failed to get thermal throttling\n"); + return rc; + } + + if (tt_data) + *tt_data = reply.evt.tt_data; + + return 0; +} + void wmi_event_flush(struct wil6210_priv *wil) { ulong flags; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 7c9fee57aa91..f7f5f4f801e3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -58,6 +58,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3, WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, WMI_FW_CAPABILITY_WMI_ONLY = 5, + WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, WMI_FW_CAPABILITY_MAX, }; @@ -142,8 +143,6 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x851, WMI_RS_MGMT_CMDID = 0x852, WMI_RF_MGMT_CMDID = 0x853, - WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854, - WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855, WMI_OTP_READ_CMDID = 0x856, WMI_OTP_WRITE_CMDID = 0x857, WMI_LED_CFG_CMDID = 0x858, @@ -192,6 +191,8 @@ enum wmi_command_id { WMI_GET_MGMT_RETRY_LIMIT_CMDID = 0x931, WMI_NEW_STA_CMDID = 0x935, WMI_DEL_STA_CMDID = 0x936, + WMI_SET_THERMAL_THROTTLING_CFG_CMDID = 0x940, + WMI_GET_THERMAL_THROTTLING_CFG_CMDID = 0x941, WMI_TOF_SESSION_START_CMDID = 0x991, WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, WMI_TOF_SET_LCR_CMDID = 0x993, @@ -438,16 +439,6 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; -/* WMI_THERMAL_THROTTLING_CTRL_CMDID */ -#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) - -/* WMI_THERMAL_THROTTLING_CTRL_CMDID */ -struct wmi_thermal_throttling_ctrl_cmd { - __le32 time_on_usec; - __le32 time_off_usec; - __le32 max_txop_length_usec; -} __packed; - /* WMI_RF_RX_TEST_CMDID */ struct wmi_rf_rx_test_cmd { __le32 sector; @@ -549,7 +540,7 @@ struct wmi_pcp_start_cmd { u8 hidden_ssid; u8 is_go; u8 reserved0[5]; - /* abft_len override if non-0 */ + /* A-BFT length override if non-0 */ u8 abft_len; u8 disable_ap_sme; u8 network_type; @@ -910,6 +901,39 @@ struct wmi_set_mgmt_retry_limit_cmd { u8 reserved[3]; } __packed; +/* Zones: HIGH, MAX, CRITICAL */ +#define WMI_NUM_OF_TT_ZONES (3) + +struct wmi_tt_zone_limits { + /* Above this temperature this zone is active */ + u8 temperature_high; + /* Below this temperature the adjacent lower zone is active */ + u8 temperature_low; + u8 reserved[2]; +} __packed; + +/* Struct used for both configuration and status commands of thermal + * throttling + */ +struct wmi_tt_data { + /* Enable/Disable TT algorithm for baseband */ + u8 bb_enabled; + u8 reserved0[3]; + /* Define zones for baseband */ + struct wmi_tt_zone_limits bb_zones[WMI_NUM_OF_TT_ZONES]; + /* Enable/Disable TT algorithm for radio */ + u8 rf_enabled; + u8 reserved1[3]; + /* Define zones for all radio chips */ + struct wmi_tt_zone_limits rf_zones[WMI_NUM_OF_TT_ZONES]; +} __packed; + +/* WMI_SET_THERMAL_THROTTLING_CFG_CMDID */ +struct wmi_set_thermal_throttling_cfg_cmd { + /* Command data */ + struct wmi_tt_data tt_data; +} __packed; + /* WMI_NEW_STA_CMDID */ struct wmi_new_sta_cmd { u8 dst_mac[WMI_MAC_LEN]; @@ -1040,7 +1064,6 @@ enum wmi_event_id { WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, - WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, @@ -1090,6 +1113,8 @@ enum wmi_event_id { WMI_BRP_SET_ANT_LIMIT_EVENTID = 0x1924, WMI_SET_MGMT_RETRY_LIMIT_EVENTID = 0x1930, WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931, + WMI_SET_THERMAL_THROTTLING_CFG_EVENTID = 0x1940, + WMI_GET_THERMAL_THROTTLING_CFG_EVENTID = 0x1941, WMI_TOF_SESSION_END_EVENTID = 0x1991, WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992, WMI_TOF_SET_LCR_EVENTID = 0x1993, @@ -1133,13 +1158,6 @@ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; -/* WMI_THERMAL_THROTTLING_STATUS_EVENTID */ -struct wmi_thermal_throttling_status_event { - __le32 time_on_usec; - __le32 time_off_usec; - __le32 max_txop_length_usec; -} __packed; - /* WMI_GET_STATUS_DONE_EVENTID */ struct wmi_get_status_done_event { __le32 is_associated; @@ -2206,6 +2224,19 @@ struct wmi_tof_get_capabilities_event { __le32 aoa_supported_types; } __packed; +/* WMI_SET_THERMAL_THROTTLING_CFG_EVENTID */ +struct wmi_set_thermal_throttling_cfg_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_GET_THERMAL_THROTTLING_CFG_EVENTID */ +struct wmi_get_thermal_throttling_cfg_event { + /* Status data */ + struct wmi_tt_data tt_data; +} __packed; + enum wmi_tof_session_end_status { WMI_TOF_SESSION_END_NO_ERROR = 0x00, WMI_TOF_SESSION_END_FAIL = 0x01, diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h index 5da6703942d9..672f81ea02d0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.h +++ b/drivers/net/wireless/realtek/rtlwifi/pci.h @@ -275,10 +275,10 @@ struct mp_adapter { }; struct rtl_pci_priv { + struct bt_coexist_info bt_coexist; + struct rtl_led_ctl ledctl; struct rtl_pci dev; struct mp_adapter ndis_adapter; - struct rtl_led_ctl ledctl; - struct bt_coexist_info bt_coexist; }; #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 5f14308e8eb3..b1601441991d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1003,7 +1003,7 @@ static void _rtl92ee_hw_configure(struct ieee80211_hw *hw) rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a); /* Note Data sheet don't define */ - rtl_write_word(rtlpriv, 0x4C7, 0x80); + rtl_write_byte(rtlpriv, 0x4C7, 0x80); rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index bbb789f8990b..c2103e7a8132 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -1127,7 +1127,7 @@ static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr) } if (0 == tmp) { read_addr = REG_DBI_RDATA + addr % 4; - ret = rtl_read_word(rtlpriv, read_addr); + ret = rtl_read_byte(rtlpriv, read_addr); } return ret; } diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index aac1ed3f7bb4..ad8390d2997b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -834,12 +834,30 @@ static void rtl_usb_stop(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct urb *urb; /* should after adapter start and interrupt enable. */ set_hal_stop(rtlhal); cancel_work_sync(&rtlpriv->works.fill_h2c_cmd); /* Enable software */ SET_USB_STOP(rtlusb); + + /* free pre-allocated URBs from rtl_usb_start() */ + usb_kill_anchored_urbs(&rtlusb->rx_submitted); + + tasklet_kill(&rtlusb->rx_work_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + + flush_workqueue(rtlpriv->works.rtl_wq); + + skb_queue_purge(&rtlusb->rx_queue); + + while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + usb_free_urb(urb); + } + rtlpriv->cfg->ops->hw_disable(hw); } @@ -1073,6 +1091,7 @@ int rtl_usb_probe(struct usb_interface *intf, return -ENOMEM; } rtlpriv = hw->priv; + rtlpriv->hw = hw; rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), GFP_KERNEL); if (!rtlpriv->usb_data) diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.h b/drivers/net/wireless/realtek/rtlwifi/usb.h index 685273ca9561..441c4412130c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.h +++ b/drivers/net/wireless/realtek/rtlwifi/usb.h @@ -150,8 +150,9 @@ struct rtl_usb { }; struct rtl_usb_priv { - struct rtl_usb dev; + struct bt_coexist_info bt_coexist; struct rtl_led_ctl ledctl; + struct rtl_usb dev; }; #define rtl_usbpriv(hw) (((struct rtl_usb_priv *)(rtl_priv(hw))->priv)) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 60654d524858..ecc6fb9ca92f 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1623,7 +1623,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, node = dev_to_node(&ndev->dev); - free_queue = ffs(nt->qp_bitmap); + free_queue = ffs(nt->qp_bitmap_free); if (!free_queue) goto err; @@ -2082,9 +2082,8 @@ module_init(ntb_transport_init); static void __exit ntb_transport_exit(void) { - debugfs_remove_recursive(nt_debugfs_dir); - ntb_unregister_client(&ntb_transport_client); bus_unregister(&ntb_transport_bus); + debugfs_remove_recursive(nt_debugfs_dir); } module_exit(ntb_transport_exit); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 62120c38d56b..aae7379af4e4 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1534,6 +1534,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) static int find_pmem_label_set(struct nd_region *nd_region, struct nd_namespace_pmem *nspm) { + u64 altcookie = nd_region_interleave_set_altcookie(nd_region); u64 cookie = nd_region_interleave_set_cookie(nd_region); struct nd_namespace_label *nd_label; u8 select_id[NSLABEL_UUID_LEN]; @@ -1542,8 +1543,10 @@ static int find_pmem_label_set(struct nd_region *nd_region, int rc = -ENODEV, l; u16 i; - if (cookie == 0) + if (cookie == 0) { + dev_dbg(&nd_region->dev, "invalid interleave-set-cookie\n"); return -ENXIO; + } /* * Find a complete set of labels by uuid. By definition we can start @@ -1552,13 +1555,24 @@ static int find_pmem_label_set(struct nd_region *nd_region, for_each_label(l, nd_label, nd_region->mapping[0].labels) { u64 isetcookie = __le64_to_cpu(nd_label->isetcookie); - if (isetcookie != cookie) - continue; + if (isetcookie != cookie) { + dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", + nd_label->uuid); + if (isetcookie != altcookie) + continue; + + dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n", + nd_label->uuid); + } + + for (i = 0; nd_region->ndr_mappings; i++) { + if (has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i)) + continue; + if (has_uuid_at_pos(nd_region, nd_label->uuid, altcookie, i)) + continue; + break; + } - for (i = 0; nd_region->ndr_mappings; i++) - if (!has_uuid_at_pos(nd_region, nd_label->uuid, - cookie, i)) - break; if (i < nd_region->ndr_mappings) { /* * Give up if we don't find an instance of a diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 417e521d299c..fc870e55bb66 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -245,6 +245,7 @@ struct nd_region *to_nd_region(struct device *dev); int nd_region_to_nstype(struct nd_region *nd_region); int nd_region_register_namespaces(struct nd_region *nd_region, int *err); u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); +u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region); void nvdimm_bus_lock(struct device *dev); void nvdimm_bus_unlock(struct device *dev); bool is_nvdimm_bus_locked(struct device *dev); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 9521696c9385..dc2e919daa39 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -379,6 +379,15 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region) return 0; } +u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region) +{ + struct nd_interleave_set *nd_set = nd_region->nd_set; + + if (nd_set) + return nd_set->altcookie; + return 0; +} + /* * Upon successful probe/remove, take/release a reference on the * associated interleave set (if present), and plant new btt + namespace diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c index 67cac25689ef..4ca5d5fa0531 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpi.c @@ -117,12 +117,12 @@ static const u32 lpi_offset[] = { 0x00005010, 0x00005020, 0x00005030, - 0x00005040, - 0x00005050, 0x00006000, 0x00006010, 0x00007000, 0x00007010, + 0x00005040, + 0x00005050, 0x00008000, 0x00008010, 0x00008020, diff --git a/drivers/platform/goldfish/pdev_bus.c b/drivers/platform/goldfish/pdev_bus.c index 1f52462f4cdd..dd9ea463c2a4 100644 --- a/drivers/platform/goldfish/pdev_bus.c +++ b/drivers/platform/goldfish/pdev_bus.c @@ -157,23 +157,26 @@ static int goldfish_new_pdev(void) static irqreturn_t goldfish_pdev_bus_interrupt(int irq, void *dev_id) { irqreturn_t ret = IRQ_NONE; + while (1) { u32 op = readl(pdev_bus_base + PDEV_BUS_OP); - switch (op) { - case PDEV_BUS_OP_DONE: - return IRQ_NONE; + switch (op) { case PDEV_BUS_OP_REMOVE_DEV: goldfish_pdev_remove(); + ret = IRQ_HANDLED; break; case PDEV_BUS_OP_ADD_DEV: goldfish_new_pdev(); + ret = IRQ_HANDLED; break; + + case PDEV_BUS_OP_DONE: + default: + return ret; } - ret = IRQ_HANDLED; } - return ret; } static int goldfish_pdev_bus_probe(struct platform_device *pdev) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 2f28ba673d5a..c8ff06ddda87 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3565,11 +3565,6 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) memset(&mem, 0, sizeof(mem)); - if (IPA_CLIENT_IS_PROD(ep->client)) { - res = gsi_stop_channel(ep->gsi_chan_hdl); - goto end_sequence; - } - for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) { IPADBG("Calling gsi_stop_channel\n"); res = gsi_stop_channel(ep->gsi_chan_hdl); @@ -3577,12 +3572,14 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT) goto end_sequence; - IPADBG("Inject a DMA_TASK with 1B packet to IPA and retry\n"); - /* Send a 1B packet DMA_TASK to IPA and try again */ - res = ipa3_inject_dma_task_for_gsi(); - if (res) { - IPAERR("Failed to inject DMA TASk for GSI\n"); - goto end_sequence; + if (IPA_CLIENT_IS_CONS(ep->client)) { + IPADBG("Inject a DMA_TASK with 1B packet to IPA\n"); + /* Send a 1B packet DMA_TASK to IPA and try again */ + res = ipa3_inject_dma_task_for_gsi(); + if (res) { + IPAERR("Failed to inject DMA TASk for GSI\n"); + goto end_sequence; + } } /* sleep for short period to flush IPA */ diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 201a53e66ef0..438da2c51dd6 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -264,6 +264,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(dp_dm), POWER_SUPPLY_ATTR(input_current_limited), POWER_SUPPLY_ATTR(input_current_now), + POWER_SUPPLY_ATTR(charge_qnovo_enable), POWER_SUPPLY_ATTR(current_qnovo), POWER_SUPPLY_ATTR(voltage_qnovo), POWER_SUPPLY_ATTR(rerun_aicl), diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 5b320ca8e74e..0c80c8be7909 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -24,7 +24,7 @@ #include <linux/printk.h> #include <linux/pm_wakeup.h> #include <linux/slab.h> -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define DRV_MAJOR_VERSION 1 #define DRV_MINOR_VERSION 0 diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 32a25b4e2c7b..0e15752eb9d2 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -29,7 +29,7 @@ #include <linux/string_helpers.h> #include <linux/types.h> #include <linux/uaccess.h> -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define fg_dbg(chip, reason, fmt, ...) \ do { \ @@ -372,6 +372,7 @@ struct fg_chip { bool esr_flt_cold_temp_en; bool bsoc_delta_irq_en; bool slope_limit_en; + bool use_ima_single_mode; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; diff --git a/drivers/power/supply/qcom/fg-memif.c b/drivers/power/supply/qcom/fg-memif.c index 2dc76182ed15..8a949bfe61d0 100644 --- a/drivers/power/supply/qcom/fg-memif.c +++ b/drivers/power/supply/qcom/fg-memif.c @@ -48,6 +48,10 @@ static int fg_config_access_mode(struct fg_chip *chip, bool access, bool burst) int rc; u8 intf_ctl = 0; + fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "access: %d burst: %d\n", + access, burst); + + WARN_ON(burst && chip->use_ima_single_mode); intf_ctl = ((access == FG_WRITE) ? IMA_WR_EN_BIT : 0) | (burst ? MEM_ACS_BURST_BIT : 0); @@ -175,6 +179,7 @@ int fg_clear_dma_errors_if_any(struct fg_chip *chip) { int rc; u8 dma_sts; + bool error_present; rc = fg_read(chip, MEM_IF_DMA_STS(chip), &dma_sts, 1); if (rc < 0) { @@ -184,14 +189,13 @@ int fg_clear_dma_errors_if_any(struct fg_chip *chip) } fg_dbg(chip, FG_STATUS, "dma_sts: %x\n", dma_sts); - if (dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT)) { - rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), - DMA_CLEAR_LOG_BIT, DMA_CLEAR_LOG_BIT); - if (rc < 0) { - pr_err("failed to write addr=0x%04x, rc=%d\n", - MEM_IF_DMA_CTL(chip), rc); - return rc; - } + error_present = dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT); + rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), DMA_CLEAR_LOG_BIT, + error_present ? DMA_CLEAR_LOG_BIT : 0); + if (rc < 0) { + pr_err("failed to write addr=0x%04x, rc=%d\n", + MEM_IF_DMA_CTL(chip), rc); + return rc; } return 0; @@ -293,7 +297,9 @@ static int fg_check_iacs_ready(struct fg_chip *chip) /* check for error condition */ rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { - pr_err("Failed to check for ima errors rc=%d\n", rc); + if (rc != -EAGAIN) + pr_err("Failed to check for ima errors rc=%d\n", + rc); return rc; } @@ -357,7 +363,12 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address, /* check for error condition */ rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { - pr_err("Failed to check for ima errors rc=%d\n", rc); + if (rc == -EAGAIN) + pr_err("IMA error cleared, address [%d %d] len %d\n", + address, offset, len); + else + pr_err("Failed to check for ima errors rc=%d\n", + rc); return rc; } @@ -365,6 +376,15 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address, len -= num_bytes; offset = byte_enable = 0; + if (chip->use_ima_single_mode && len) { + address++; + rc = fg_set_address(chip, address); + if (rc < 0) { + pr_err("failed to set address rc = %d\n", rc); + return rc; + } + } + rc = fg_check_iacs_ready(chip); if (rc < 0) { pr_debug("IACS_RDY failed rc=%d\n", rc); @@ -403,22 +423,40 @@ static int __fg_interleaved_mem_read(struct fg_chip *chip, u16 address, /* check for error condition */ rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { - pr_err("Failed to check for ima errors rc=%d\n", rc); + if (rc == -EAGAIN) + pr_err("IMA error cleared, address [%d %d] len %d\n", + address, offset, len); + else + pr_err("Failed to check for ima errors rc=%d\n", + rc); return rc; } - if (len && len < BYTES_PER_SRAM_WORD) { - /* - * Move to single mode. Changing address is not - * required here as it must be in burst mode. Address - * will get incremented internally by FG HW once the MSB - * of RD_DATA is read. - */ - rc = fg_config_access_mode(chip, FG_READ, 0); - if (rc < 0) { - pr_err("failed to move to single mode rc=%d\n", - rc); - return -EIO; + if (chip->use_ima_single_mode) { + if (len) { + address++; + rc = fg_set_address(chip, address); + if (rc < 0) { + pr_err("failed to set address rc = %d\n", + rc); + return rc; + } + } + } else { + if (len && len < BYTES_PER_SRAM_WORD) { + /* + * Move to single mode. Changing address is not + * required here as it must be in burst mode. + * Address will get incremented internally by FG + * HW once the MSB of RD_DATA is read. + */ + rc = fg_config_access_mode(chip, FG_READ, + false); + if (rc < 0) { + pr_err("failed to move to single mode rc=%d\n", + rc); + return -EIO; + } } } @@ -489,6 +527,7 @@ static int fg_interleaved_mem_config(struct fg_chip *chip, u8 *val, u16 address, int offset, int len, bool access) { int rc = 0; + bool burst_mode = false; if (!is_mem_access_available(chip, access)) return -EBUSY; @@ -503,7 +542,8 @@ static int fg_interleaved_mem_config(struct fg_chip *chip, u8 *val, } /* configure for the read/write, single/burst mode */ - rc = fg_config_access_mode(chip, access, (offset + len) > 4); + burst_mode = chip->use_ima_single_mode ? false : ((offset + len) > 4); + rc = fg_config_access_mode(chip, access, burst_mode); if (rc < 0) { pr_err("failed to set memory access rc = %d\n", rc); return rc; @@ -583,7 +623,7 @@ retry: if (rc < 0) { count++; if (rc == -EAGAIN) { - pr_err("IMA access failed retry_count = %d\n", count); + pr_err("IMA read failed retry_count = %d\n", count); goto retry; } pr_err("failed to read SRAM address rc = %d\n", rc); @@ -667,8 +707,8 @@ retry: rc = __fg_interleaved_mem_write(chip, address, offset, val, len); if (rc < 0) { count++; - if ((rc == -EAGAIN) && (count < RETRY_COUNT)) { - pr_err("IMA access failed retry_count = %d\n", count); + if (rc == -EAGAIN) { + pr_err("IMA write failed retry_count = %d\n", count); goto retry; } pr_err("failed to write SRAM address rc = %d\n", rc); diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c index c07e9f083204..3652cc7802eb 100644 --- a/drivers/power/supply/qcom/pmic-voter.c +++ b/drivers/power/supply/qcom/pmic-voter.c @@ -18,7 +18,7 @@ #include <linux/slab.h> #include <linux/string.h> -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define NUM_MAX_CLIENTS 8 #define DEBUG_FORCE_CLIENT "DEBUG_FORCE_CLIENT" diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 5dcd4c36675a..aeffe1f154a1 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -525,7 +525,7 @@ static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id, } #define CC_SOC_30BIT GENMASK(29, 0) -static int fg_get_cc_soc(struct fg_chip *chip, int *val) +static int fg_get_charge_raw(struct fg_chip *chip, int *val) { int rc, cc_soc; @@ -539,7 +539,7 @@ static int fg_get_cc_soc(struct fg_chip *chip, int *val) return 0; } -static int fg_get_cc_soc_sw(struct fg_chip *chip, int *val) +static int fg_get_charge_counter(struct fg_chip *chip, int *val) { int rc, cc_soc; @@ -1241,7 +1241,7 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah); } -static int fg_cap_learning_process_full_data(struct fg_chip *chip) +static int fg_cap_learning_process_full_data(struct fg_chip *chip) { int rc, cc_soc_sw, cc_soc_delta_pct; int64_t delta_cc_uah; @@ -1263,30 +1263,39 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip) return 0; } -static int fg_cap_learning_begin(struct fg_chip *chip, int batt_soc) +#define BATT_SOC_32BIT GENMASK(31, 0) +static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc) { - int rc, cc_soc_sw; + int rc, cc_soc_sw, batt_soc_msb; - if (DIV_ROUND_CLOSEST(batt_soc * 100, FULL_SOC_RAW) > + batt_soc_msb = batt_soc >> 24; + if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) > chip->dt.cl_start_soc) { fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n", - batt_soc); + batt_soc_msb); return -EINVAL; } - chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc, + chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb, FULL_SOC_RAW); - rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw); + + /* Prime cc_soc_sw with battery SOC when capacity learning begins */ + cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT, + BATT_SOC_32BIT); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word, + chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw, + chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC); if (rc < 0) { - pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc); - return rc; + pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); + goto out; } chip->cl.init_cc_soc_sw = cc_soc_sw; chip->cl.active = true; fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", - batt_soc, chip->cl.init_cc_soc_sw); - return 0; + batt_soc_msb, chip->cl.init_cc_soc_sw); +out: + return rc; } static int fg_cap_learning_done(struct fg_chip *chip) @@ -1318,7 +1327,7 @@ out: #define FULL_SOC_RAW 255 static void fg_cap_learning_update(struct fg_chip *chip) { - int rc, batt_soc; + int rc, batt_soc, batt_soc_msb; mutex_lock(&chip->cl.lock); @@ -1337,11 +1346,9 @@ static void fg_cap_learning_update(struct fg_chip *chip) goto out; } - /* We need only the most significant byte here */ - batt_soc = (u32)batt_soc >> 24; - + batt_soc_msb = (u32)batt_soc >> 24; fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n", - chip->charge_status, chip->cl.active, batt_soc); + chip->charge_status, chip->cl.active, batt_soc_msb); /* Initialize the starting point of learning capacity */ if (!chip->cl.active) { @@ -1363,7 +1370,7 @@ static void fg_cap_learning_update(struct fg_chip *chip) if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n", - batt_soc); + batt_soc_msb); chip->cl.active = false; chip->cl.init_cc_uah = 0; } @@ -1598,6 +1605,9 @@ static int fg_rconn_config(struct fg_chip *chip) u64 scaling_factor; u32 val = 0; + if (!chip->dt.rconn_mohms) + return 0; + rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD, SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { @@ -2818,7 +2828,7 @@ static int fg_psy_get_property(struct power_supply *psy, pval->intval = chip->cyc_ctr.id; break; case POWER_SUPPLY_PROP_CHARGE_NOW_RAW: - rc = fg_get_cc_soc(chip, &pval->intval); + rc = fg_get_charge_raw(chip, &pval->intval); break; case POWER_SUPPLY_PROP_CHARGE_NOW: pval->intval = chip->cl.init_cc_uah; @@ -2827,7 +2837,7 @@ static int fg_psy_get_property(struct power_supply *psy, pval->intval = chip->cl.learned_cc_uah; break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: - rc = fg_get_cc_soc_sw(chip, &pval->intval); + rc = fg_get_charge_counter(chip, &pval->intval); break; case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: rc = fg_get_time_to_full(chip, &pval->intval); @@ -3176,12 +3186,10 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - if (chip->dt.rconn_mohms > 0) { - rc = fg_rconn_config(chip); - if (rc < 0) { - pr_err("Error in configuring Rconn, rc=%d\n", rc); - return rc; - } + rc = fg_rconn_config(chip); + if (rc < 0) { + pr_err("Error in configuring Rconn, rc=%d\n", rc); + return rc; } fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, @@ -3228,20 +3236,19 @@ static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) } fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status); - if (status & MEM_XCP_BIT) { - rc = fg_clear_dma_errors_if_any(chip); - if (rc < 0) { - pr_err("Error in clearing DMA error, rc=%d\n", rc); - return IRQ_HANDLED; - } - mutex_lock(&chip->sram_rw_lock); + mutex_lock(&chip->sram_rw_lock); + rc = fg_clear_dma_errors_if_any(chip); + if (rc < 0) + pr_err("Error in clearing DMA error, rc=%d\n", rc); + + if (status & MEM_XCP_BIT) { rc = fg_clear_ima_errors_if_any(chip, true); if (rc < 0 && rc != -EAGAIN) pr_err("Error in checking IMA errors rc:%d\n", rc); - mutex_unlock(&chip->sram_rw_lock); } + mutex_unlock(&chip->sram_rw_lock); return IRQ_HANDLED; } @@ -3737,6 +3744,7 @@ static int fg_parse_dt(struct fg_chip *chip) case PM660_SUBTYPE: chip->sp = pmi8998_v2_sram_params; chip->alg_flags = pmi8998_v2_alg_flags; + chip->use_ima_single_mode = true; break; default: return -EINVAL; @@ -3957,9 +3965,7 @@ static int fg_parse_dt(struct fg_chip *chip) pr_err("Error in parsing Ki coefficients, rc=%d\n", rc); rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp); - if (rc < 0) - chip->dt.rconn_mohms = -EINVAL; - else + if (!rc) chip->dt.rconn_mohms = temp; rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp", diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index d36db8d8f3f1..8f9514a25f63 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo.c +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -19,7 +19,7 @@ #include <linux/of.h> #include <linux/of_irq.h> #include <linux/qpnp/qpnp-revid.h> -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define QNOVO_REVISION1 0x00 #define QNOVO_REVISION2 0x01 @@ -29,6 +29,7 @@ #define QNOVO_PTRAIN_STS 0x08 #define QNOVO_ERROR_STS 0x09 #define QNOVO_ERROR_BIT BIT(0) +#define QNOVO_ERROR_STS2 0x0A #define QNOVO_INT_RT_STS 0x10 #define QNOVO_INT_SET_TYPE 0x11 #define QNOVO_INT_POLARITY_HIGH 0x12 @@ -151,7 +152,7 @@ struct qnovo { }; static int debug_mask; -module_param_named(debug_mask, debug_mask, int, S_IRUSR | S_IWUSR); +module_param_named(debug_mask, debug_mask, int, 0600); #define qnovo_dbg(chip, reason, fmt, ...) \ do { \ @@ -272,28 +273,22 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, const char *client) { struct qnovo *chip = data; - int rc = 0; + union power_supply_propval pval = {0}; + int rc; - if (disable) { - rc = qnovo_batt_psy_update(chip, true); - if (rc < 0) - return rc; - } + if (!is_batt_available(chip)) + return -EINVAL; - rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, - disable ? 0 : QNOVO_PTRAIN_EN_BIT); + pval.intval = !disable; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, + &pval); if (rc < 0) { - dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", - disable ? "disable" : "enable", rc); - return rc; - } - - if (!disable) { - rc = qnovo_batt_psy_update(chip, false); - if (rc < 0) - return rc; + pr_err("Couldn't set prop qnovo_enable rc = %d\n", rc); + return -EINVAL; } + rc = qnovo_batt_psy_update(chip, disable); return rc; } @@ -348,13 +343,15 @@ static int qnovo_check_chg_version(struct qnovo *chip) enum { VER = 0, OK_TO_QNOVO, - ENABLE, + QNOVO_ENABLE, + PT_ENABLE, FV_REQUEST, FCC_REQUEST, PE_CTRL_REG, PE_CTRL2_REG, PTRAIN_STS_REG, INT_RT_STS_REG, + ERR_STS2_REG, PREST1, PPULS1, NREST1, @@ -394,6 +391,12 @@ struct param_info { }; static struct param_info params[] = { + [PT_ENABLE] = { + .name = "PT_ENABLE", + .start_addr = QNOVO_PTRAIN_EN, + .num_regs = 1, + .units_str = "", + }, [FV_REQUEST] = { .units_str = "uV", }, @@ -424,6 +427,12 @@ static struct param_info params[] = { .num_regs = 1, .units_str = "", }, + [ERR_STS2_REG] = { + .name = "RAW_CHGR_ERR", + .start_addr = QNOVO_ERROR_STS2, + .num_regs = 1, + .units_str = "", + }, [PREST1] = { .name = "PREST1", .start_addr = QNOVO_PREST1_CTRL, @@ -431,7 +440,7 @@ static struct param_info params[] = { .reg_to_unit_multiplier = 5, .reg_to_unit_divider = 1, .min_val = 5, - .max_val = 1275, + .max_val = 255, .units_str = "mS", }, [PPULS1] = { @@ -440,8 +449,8 @@ static struct param_info params[] = { .num_regs = 2, .reg_to_unit_multiplier = 1600, /* converts to uC */ .reg_to_unit_divider = 1, - .min_val = 0, - .max_val = 104856000, + .min_val = 30000, + .max_val = 65535000, .units_str = "uC", }, [NREST1] = { @@ -451,7 +460,7 @@ static struct param_info params[] = { .reg_to_unit_multiplier = 5, .reg_to_unit_divider = 1, .min_val = 5, - .max_val = 1275, + .max_val = 255, .units_str = "mS", }, [NPULS1] = { @@ -460,8 +469,8 @@ static struct param_info params[] = { .num_regs = 1, .reg_to_unit_multiplier = 5, .reg_to_unit_divider = 1, - .min_val = 5, - .max_val = 1275, + .min_val = 0, + .max_val = 255, .units_str = "mS", }, [PPCNT] = { @@ -470,7 +479,7 @@ static struct param_info params[] = { .num_regs = 1, .reg_to_unit_multiplier = 1, .reg_to_unit_divider = 1, - .min_val = 0, + .min_val = 1, .max_val = 255, .units_str = "pulses", }, @@ -480,8 +489,8 @@ static struct param_info params[] = { .num_regs = 2, .reg_to_unit_multiplier = 610350, /* converts to nV */ .reg_to_unit_divider = 1, - .min_val = 0, - .max_val = 5000000, + .min_val = 2200000, + .max_val = 4500000, .units_str = "uV", }, [PVOLT1] = { @@ -506,8 +515,6 @@ static struct param_info params[] = { .num_regs = 1, .reg_to_unit_multiplier = 2, .reg_to_unit_divider = 1, - .min_val = 5, - .max_val = 1275, .units_str = "S", }, [PREST2] = { @@ -517,7 +524,7 @@ static struct param_info params[] = { .reg_to_unit_multiplier = 5, .reg_to_unit_divider = 1, .min_val = 5, - .max_val = 327675, + .max_val = 65535, .units_str = "mS", }, [PPULS2] = { @@ -526,8 +533,8 @@ static struct param_info params[] = { .num_regs = 2, .reg_to_unit_multiplier = 1600, /* converts to uC */ .reg_to_unit_divider = 1, - .min_val = 0, - .max_val = 104856000, + .min_val = 30000, + .max_val = 65535000, .units_str = "uC", }, [NREST2] = { @@ -538,7 +545,7 @@ static struct param_info params[] = { .reg_to_unit_divider = 1, .reg_to_unit_offset = -5, .min_val = 5, - .max_val = 1280, + .max_val = 255, .units_str = "mS", }, [NPULS2] = { @@ -547,18 +554,18 @@ static struct param_info params[] = { .num_regs = 1, .reg_to_unit_multiplier = 5, .reg_to_unit_divider = 1, - .min_val = 5, - .max_val = 1275, + .min_val = 0, + .max_val = 255, .units_str = "mS", }, [VLIM2] = { - .name = "VLIM1", + .name = "VLIM2", .start_addr = QNOVO_VLIM2_LSB_CTRL, .num_regs = 2, .reg_to_unit_multiplier = 610350, /* converts to nV */ .reg_to_unit_divider = 1, - .min_val = 0, - .max_val = 5000000, + .min_val = 2200000, + .max_val = 4500000, .units_str = "uV", }, [PVOLT2] = { @@ -591,6 +598,8 @@ static struct param_info params[] = { .num_regs = 1, .reg_to_unit_multiplier = 1, .reg_to_unit_divider = 1, + .min_val = 0, + .max_val = 255, .units_str = "pulses", }, [VMAX] = { @@ -648,30 +657,70 @@ static ssize_t ok_to_qnovo_show(struct class *c, struct class_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", chip->cs.ok_to_qnovo); } -static ssize_t enable_show(struct class *c, struct class_attribute *attr, +static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr, char *ubuf) { struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); - int val; + int val = get_effective_result(chip->disable_votable); - val = get_client_vote(chip->disable_votable, USER_VOTER); - val = !val; - return snprintf(ubuf, PAGE_SIZE, "%d\n", val); + return snprintf(ubuf, PAGE_SIZE, "%d\n", !val); +} + +static ssize_t qnovo_enable_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + unsigned long val; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + vote(chip->disable_votable, USER_VOTER, !val, 0); + + return count; +} + +static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = attr - qnovo_attributes; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + u16 regval; + int rc; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval = buf[1] << 8 | buf[0]; + + return snprintf(ubuf, PAGE_SIZE, "%d\n", + (int)(regval & QNOVO_PTRAIN_EN_BIT)); } -static ssize_t enable_store(struct class *c, struct class_attribute *attr, +static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr, const char *ubuf, size_t count) { struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); unsigned long val; - bool disable; + int rc = 0; - if (kstrtoul(ubuf, 10, &val)) + if (get_effective_result(chip->disable_votable)) return -EINVAL; - disable = !val; + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, + (bool)val ? QNOVO_PTRAIN_EN_BIT : 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", + (bool)val ? "enable" : "disable", rc); + return rc; + } - vote(chip->disable_votable, USER_VOTER, disable, 0); return count; } @@ -688,7 +737,7 @@ static ssize_t val_show(struct class *c, struct class_attribute *attr, if (i == FCC_REQUEST) val = chip->fcc_uA_request; - return snprintf(ubuf, PAGE_SIZE, "%d%s\n", val, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "%d\n", val); } static ssize_t val_store(struct class *c, struct class_attribute *attr, @@ -698,7 +747,10 @@ static ssize_t val_store(struct class *c, struct class_attribute *attr, int i = attr - qnovo_attributes; unsigned long val; - if (kstrtoul(ubuf, 10, &val)) + if (get_effective_result(chip->disable_votable)) + return -EINVAL; + + if (kstrtoul(ubuf, 0, &val)) return -EINVAL; if (i == FV_REQUEST) @@ -707,6 +759,8 @@ static ssize_t val_store(struct class *c, struct class_attribute *attr, if (i == FCC_REQUEST) chip->fcc_uA_request = val; + qnovo_batt_psy_update(chip, false); + return count; } @@ -726,8 +780,7 @@ static ssize_t reg_show(struct class *c, struct class_attribute *attr, } regval = buf[1] << 8 | buf[0]; - return snprintf(ubuf, PAGE_SIZE, "0x%04x%s\n", - regval, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "0x%04x\n", regval); } static ssize_t reg_store(struct class *c, struct class_attribute *attr, @@ -739,7 +792,7 @@ static ssize_t reg_store(struct class *c, struct class_attribute *attr, unsigned long val; int rc; - if (kstrtoul(ubuf, 16, &val)) + if (kstrtoul(ubuf, 0, &val)) return -EINVAL; buf[0] = val & 0xFF; @@ -774,7 +827,7 @@ static ssize_t time_show(struct class *c, struct class_attribute *attr, / params[i].reg_to_unit_divider) - params[i].reg_to_unit_offset; - return snprintf(ubuf, PAGE_SIZE, "%d%s\n", val, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "%d\n", val); } static ssize_t time_store(struct class *c, struct class_attribute *attr, @@ -787,7 +840,7 @@ static ssize_t time_store(struct class *c, struct class_attribute *attr, unsigned long val; int rc; - if (kstrtoul(ubuf, 10, &val)) + if (kstrtoul(ubuf, 0, &val)) return -EINVAL; if (val < params[i].min_val || val > params[i].max_val) { @@ -841,11 +894,10 @@ static ssize_t current_show(struct class *c, struct class_attribute *attr, gain = chip->internal_i_gain_mega; } - comp_val_nA = div_s64(regval_nA * gain, 1000000) + offset_nA; + comp_val_nA = div_s64(regval_nA * gain, 1000000) - offset_nA; comp_val_uA = div_s64(comp_val_nA, 1000); - return snprintf(ubuf, PAGE_SIZE, "%d%s\n", - comp_val_uA, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uA); } static ssize_t voltage_show(struct class *c, struct class_attribute *attr, @@ -875,8 +927,7 @@ static ssize_t voltage_show(struct class *c, struct class_attribute *attr, comp_val_nV = div_s64(regval_nV * gain, 1000000) + offset_nV; comp_val_uV = div_s64(comp_val_nV, 1000); - return snprintf(ubuf, PAGE_SIZE, "%d%s\n", - comp_val_uV, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uV); } static ssize_t voltage_store(struct class *c, struct class_attribute *attr, @@ -890,7 +941,7 @@ static ssize_t voltage_store(struct class *c, struct class_attribute *attr, s64 regval_nV; s64 gain, offset_nV; - if (kstrtoul(ubuf, 10, &val_uV)) + if (kstrtoul(ubuf, 0, &val_uV)) return -EINVAL; if (val_uV < params[i].min_val || val_uV > params[i].max_val) { @@ -947,8 +998,7 @@ static ssize_t coulomb_show(struct class *c, struct class_attribute *attr, gain = chip->internal_i_gain_mega; comp_val_uC = div_s64(regval_uC * gain, 1000000); - return snprintf(ubuf, PAGE_SIZE, "%d%s\n", - comp_val_uC, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uC); } static ssize_t coulomb_store(struct class *c, struct class_attribute *attr, @@ -962,7 +1012,7 @@ static ssize_t coulomb_store(struct class *c, struct class_attribute *attr, s64 regval; s64 gain; - if (kstrtoul(ubuf, 10, &val_uC)) + if (kstrtoul(ubuf, 0, &val_uC)) return -EINVAL; if (val_uC < params[i].min_val || val_uC > params[i].max_val) { @@ -1014,74 +1064,75 @@ static ssize_t batt_prop_show(struct class *c, struct class_attribute *attr, return -EINVAL; } - return snprintf(ubuf, PAGE_SIZE, "%d%s\n", - pval.intval, params[i].units_str); + return snprintf(ubuf, PAGE_SIZE, "%d\n", pval.intval); } static struct class_attribute qnovo_attributes[] = { [VER] = __ATTR_RO(version), [OK_TO_QNOVO] = __ATTR_RO(ok_to_qnovo), - [ENABLE] = __ATTR(enable, S_IRUGO | S_IWUSR, - enable_show, enable_store), - [FV_REQUEST] = __ATTR(fv_uV_request, S_IRUGO | S_IWUSR, + [QNOVO_ENABLE] = __ATTR_RW(qnovo_enable), + [PT_ENABLE] = __ATTR_RW(pt_enable), + [FV_REQUEST] = __ATTR(fv_uV_request, 0644, val_show, val_store), - [FCC_REQUEST] = __ATTR(fcc_uA_request, S_IRUGO | S_IWUSR, + [FCC_REQUEST] = __ATTR(fcc_uA_request, 0644, val_show, val_store), - [PE_CTRL_REG] = __ATTR(PE_CTRL_REG, S_IRUGO | S_IWUSR, - reg_show, reg_store), - [PE_CTRL2_REG] = __ATTR(PE_CTRL2_REG, S_IRUGO | S_IWUSR, + [PE_CTRL_REG] = __ATTR(PE_CTRL_REG, 0644, reg_show, reg_store), - [PTRAIN_STS_REG] = __ATTR(PTRAIN_STS_REG, S_IRUGO | S_IWUSR, + [PE_CTRL2_REG] = __ATTR(PE_CTRL2_REG, 0644, reg_show, reg_store), - [INT_RT_STS_REG] = __ATTR(INT_RT_STS_REG, S_IRUGO | S_IWUSR, - reg_show, reg_store), - [PREST1] = __ATTR(PREST1_mS, S_IRUGO | S_IWUSR, + [PTRAIN_STS_REG] = __ATTR(PTRAIN_STS_REG, 0444, + reg_show, NULL), + [INT_RT_STS_REG] = __ATTR(INT_RT_STS_REG, 0444, + reg_show, NULL), + [ERR_STS2_REG] = __ATTR(ERR_STS2_REG, 0444, + reg_show, NULL), + [PREST1] = __ATTR(PREST1_mS, 0644, time_show, time_store), - [PPULS1] = __ATTR(PPULS1_uC, S_IRUGO | S_IWUSR, + [PPULS1] = __ATTR(PPULS1_uC, 0644, coulomb_show, coulomb_store), - [NREST1] = __ATTR(NREST1_mS, S_IRUGO | S_IWUSR, + [NREST1] = __ATTR(NREST1_mS, 0644, time_show, time_store), - [NPULS1] = __ATTR(NPULS1_mS, S_IRUGO | S_IWUSR, + [NPULS1] = __ATTR(NPULS1_mS, 0644, time_show, time_store), - [PPCNT] = __ATTR(PPCNT, S_IRUGO | S_IWUSR, + [PPCNT] = __ATTR(PPCNT, 0644, time_show, time_store), - [VLIM1] = __ATTR(VLIM1_uV, S_IRUGO | S_IWUSR, + [VLIM1] = __ATTR(VLIM1_uV, 0644, voltage_show, voltage_store), - [PVOLT1] = __ATTR(PVOLT1_uV, S_IRUGO, + [PVOLT1] = __ATTR(PVOLT1_uV, 0444, voltage_show, NULL), - [PCUR1] = __ATTR(PCUR1_uA, S_IRUGO, + [PCUR1] = __ATTR(PCUR1_uA, 0444, current_show, NULL), - [PTTIME] = __ATTR(PTTIME_S, S_IRUGO, + [PTTIME] = __ATTR(PTTIME_S, 0444, time_show, NULL), - [PREST2] = __ATTR(PREST2_mS, S_IRUGO | S_IWUSR, + [PREST2] = __ATTR(PREST2_mS, 0644, time_show, time_store), - [PPULS2] = __ATTR(PPULS2_mS, S_IRUGO | S_IWUSR, + [PPULS2] = __ATTR(PPULS2_uC, 0644, coulomb_show, coulomb_store), - [NREST2] = __ATTR(NREST2_mS, S_IRUGO | S_IWUSR, + [NREST2] = __ATTR(NREST2_mS, 0644, time_show, time_store), - [NPULS2] = __ATTR(NPULS2_mS, S_IRUGO | S_IWUSR, + [NPULS2] = __ATTR(NPULS2_mS, 0644, time_show, time_store), - [VLIM2] = __ATTR(VLIM2_uV, S_IRUGO | S_IWUSR, + [VLIM2] = __ATTR(VLIM2_uV, 0644, voltage_show, voltage_store), - [PVOLT2] = __ATTR(PVOLT2_uV, S_IRUGO, + [PVOLT2] = __ATTR(PVOLT2_uV, 0444, voltage_show, NULL), - [RVOLT2] = __ATTR(RVOLT2_uV, S_IRUGO, + [RVOLT2] = __ATTR(RVOLT2_uV, 0444, voltage_show, NULL), - [PCUR2] = __ATTR(PCUR2_uA, S_IRUGO, + [PCUR2] = __ATTR(PCUR2_uA, 0444, current_show, NULL), - [SCNT] = __ATTR(SCNT, S_IRUGO | S_IWUSR, + [SCNT] = __ATTR(SCNT, 0644, time_show, time_store), - [VMAX] = __ATTR(VMAX_uV, S_IRUGO, + [VMAX] = __ATTR(VMAX_uV, 0444, voltage_show, NULL), - [SNUM] = __ATTR(SNUM, S_IRUGO | S_IWUSR, - time_show, time_store), - [VBATT] = __ATTR(VBATT_uV, S_IRUGO, + [SNUM] = __ATTR(SNUM, 0444, + time_show, NULL), + [VBATT] = __ATTR(VBATT_uV, 0444, batt_prop_show, NULL), - [IBATT] = __ATTR(IBATT_uA, S_IRUGO, + [IBATT] = __ATTR(IBATT_uA, 0444, batt_prop_show, NULL), - [BATTTEMP] = __ATTR(BATTTEMP_deciDegC, S_IRUGO, + [BATTTEMP] = __ATTR(BATTTEMP_deciDegC, 0444, batt_prop_show, NULL), - [BATTSOC] = __ATTR(BATTSOC, S_IRUGO, + [BATTSOC] = __ATTR(BATTSOC, 0444, batt_prop_show, NULL), __ATTR_NULL, }; @@ -1140,8 +1191,7 @@ static void get_chg_status(struct qnovo *chip, const struct chg_props *cp, { cs->ok_to_qnovo = false; - if (cp->charging && - (cp->usb_online || cp->dc_online)) + if (cp->charging && (cp->usb_online || cp->dc_online)) cs->ok_to_qnovo = true; } @@ -1157,17 +1207,10 @@ static void status_change_work(struct work_struct *work) get_chg_status(chip, &cp, &cs); if (cs.ok_to_qnovo ^ chip->cs.ok_to_qnovo) { - /* - * when it is not okay to Qnovo charge, disable both voters, - * so that when it becomes okay to Qnovo charge the user voter - * has to specifically enable its vote to being Qnovo charging - */ - if (!cs.ok_to_qnovo) { - vote(chip->disable_votable, OK_TO_QNOVO_VOTER, 1, 0); - vote(chip->disable_votable, USER_VOTER, 1, 0); - } else { - vote(chip->disable_votable, OK_TO_QNOVO_VOTER, 0, 0); - } + vote(chip->disable_votable, OK_TO_QNOVO_VOTER, + !cs.ok_to_qnovo, 0); + if (!cs.ok_to_qnovo) + vote(chip->disable_votable, USER_VOTER, true, 0); notify_uevent = true; } @@ -1197,8 +1240,6 @@ static irqreturn_t handle_ptrain_done(int irq, void *data) { struct qnovo *chip = data; - /* disable user voter here */ - vote(chip->disable_votable, USER_VOTER, 0, 0); kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); return IRQ_HANDLED; } @@ -1211,7 +1252,14 @@ static int qnovo_hw_init(struct qnovo *chip) u8 vadc_offset, vadc_gain; u8 val; - vote(chip->disable_votable, USER_VOTER, 1, 0); + vote(chip->disable_votable, USER_VOTER, true, 0); + + val = 0; + rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); + if (rc < 0) { + pr_err("Couldn't write iadc bitstream control rc = %d\n", rc); + return rc; + } rc = qnovo_read(chip, QNOVO_IADC_OFFSET_0, &iadc_offset_external, 1); if (rc < 0) { @@ -1219,12 +1267,28 @@ static int qnovo_hw_init(struct qnovo *chip) return rc; } + /* stored as an 8 bit 2's complement signed integer */ + val = -1 * iadc_offset_external; + rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1); + if (rc < 0) { + pr_err("Couldn't write iadc offset rc = %d\n", rc); + return rc; + } + rc = qnovo_read(chip, QNOVO_IADC_OFFSET_1, &iadc_offset_internal, 1); if (rc < 0) { pr_err("Couldn't read iadc internal offset rc = %d\n", rc); return rc; } + /* stored as an 8 bit 2's complement signed integer */ + val = -1 * iadc_offset_internal; + rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1); + if (rc < 0) { + pr_err("Couldn't write iadc offset rc = %d\n", rc); + return rc; + } + rc = qnovo_read(chip, QNOVO_IADC_GAIN_0, &iadc_gain_external, 1); if (rc < 0) { pr_err("Couldn't read iadc external gain rc = %d\n", rc); @@ -1249,53 +1313,20 @@ static int qnovo_hw_init(struct qnovo *chip) return rc; } - chip->external_offset_nA = (s64)iadc_offset_external * IADC_LSB_NA; - chip->internal_offset_nA = (s64)iadc_offset_internal * IADC_LSB_NA; - chip->offset_nV = (s64)vadc_offset * VADC_LSB_NA; + chip->external_offset_nA = (s64)(s8)iadc_offset_external * IADC_LSB_NA; + chip->internal_offset_nA = (s64)(s8)iadc_offset_internal * IADC_LSB_NA; + chip->offset_nV = (s64)(s8)vadc_offset * VADC_LSB_NA; chip->external_i_gain_mega - = 1000000000 + (s64)iadc_gain_external * GAIN_LSB_FACTOR; + = 1000000000 + (s64)(s8)iadc_gain_external * GAIN_LSB_FACTOR; chip->external_i_gain_mega = div_s64(chip->external_i_gain_mega, 1000); chip->internal_i_gain_mega - = 1000000000 + (s64)iadc_gain_internal * GAIN_LSB_FACTOR; + = 1000000000 + (s64)(s8)iadc_gain_internal * GAIN_LSB_FACTOR; chip->internal_i_gain_mega = div_s64(chip->internal_i_gain_mega, 1000); - chip->v_gain_mega = 1000000000 + (s64)vadc_gain * GAIN_LSB_FACTOR; + chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR; chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000); - val = 0; - rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); - if (rc < 0) { - pr_err("Couldn't write iadc bitsteam control rc = %d\n", rc); - return rc; - } - - rc = qnovo_read(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1); - if (rc < 0) { - pr_err("Couldn't read iadc offset rc = %d\n", rc); - return rc; - } - - val *= -1; - rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1); - if (rc < 0) { - pr_err("Couldn't write iadc offset rc = %d\n", rc); - return rc; - } - - rc = qnovo_read(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1); - if (rc < 0) { - pr_err("Couldn't read iadc offset rc = %d\n", rc); - return rc; - } - - val *= -1; - rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1); - if (rc < 0) { - pr_err("Couldn't write iadc offset rc = %d\n", rc); - return rc; - } - return 0; } @@ -1333,6 +1364,9 @@ static int qnovo_request_interrupts(struct qnovo *chip) irq_ptrain_done, rc); return rc; } + + enable_irq_wake(irq_ptrain_done); + return rc; } @@ -1414,6 +1448,8 @@ static int qnovo_probe(struct platform_device *pdev) goto unreg_notifier; } + device_init_wakeup(chip->dev, true); + return rc; unreg_notifier: diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 26f47df73c2f..e8249163e948 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -26,7 +26,7 @@ #include "smb-reg.h" #include "smb-lib.h" #include "storm-watch.h" -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define SMB2_DEFAULT_WPWR_UW 8000000 @@ -838,7 +838,9 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_QNOVO, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_QNOVO, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TECHNOLOGY, @@ -910,6 +912,9 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: val->intval = get_client_vote(chg->fv_votable, DEFAULT_VOTER); break; + case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE: + rc = smblib_get_prop_charge_qnovo_enable(chg, val); + break; case POWER_SUPPLY_PROP_VOLTAGE_QNOVO: val->intval = chg->qnovo_fv_uv; break; @@ -985,12 +990,17 @@ static int smb2_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval); break; + case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE: + rc = smblib_set_prop_charge_qnovo_enable(chg, val); + break; case POWER_SUPPLY_PROP_VOLTAGE_QNOVO: chg->qnovo_fv_uv = val->intval; rc = rerun_election(chg->fv_votable); break; case POWER_SUPPLY_PROP_CURRENT_QNOVO: chg->qnovo_fcc_ua = val->intval; + vote(chg->pl_disable_votable, PL_QNOVO_VOTER, + val->intval != -EINVAL && val->intval < 2000000, 0); rc = rerun_election(chg->fcc_votable); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: @@ -1534,13 +1544,6 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } - rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG, - QNOVO_PT_ENABLE_CMD_BIT, QNOVO_PT_ENABLE_CMD_BIT); - if (rc < 0) { - dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc); - return rc; - } - /* configure step charging */ rc = smb2_config_step_charging(chip); if (rc < 0) { @@ -1653,6 +1656,15 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } +static int smb2_post_init(struct smb2 *chip) +{ + struct smb_charger *chg = &chip->chg; + + rerun_election(chg->usb_irq_enable_votable); + + return 0; +} + static int smb2_chg_config_init(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; @@ -2182,6 +2194,8 @@ static int smb2_probe(struct platform_device *pdev) goto cleanup; } + smb2_post_init(chip); + smb2_create_debugfs(chip); rc = smblib_get_prop_usb_present(chg, &val); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 53bba35033a3..50af1087278a 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -22,7 +22,7 @@ #include "smb-lib.h" #include "smb-reg.h" #include "storm-watch.h" -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ @@ -1130,6 +1130,26 @@ static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable, return rc; } +static int smblib_usb_irq_enable_vote_callback(struct votable *votable, + void *data, int enable, const char *client) +{ + struct smb_charger *chg = data; + + if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq || + !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) + return 0; + + if (enable) { + enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq); + enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); + } else { + disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq); + disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); + } + + return 0; +} + /******************* * VCONN REGULATOR * * *****************/ @@ -1702,6 +1722,23 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg, return 0; } +int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + u8 stat; + + rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n", + rc); + return rc; + } + + val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT); + return 0; +} + /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -1766,6 +1803,22 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, return 0; } +int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc = 0; + + rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG, + QNOVO_PT_ENABLE_CMD_BIT, + val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc); + return rc; + } + + return rc; +} + int smblib_rerun_aicl(struct smb_charger *chg) { int rc, settled_icl_ua; @@ -2491,6 +2544,7 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0); vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0); + vote(chg->usb_irq_enable_votable, PD_VOTER, pd_active, 0); /* * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line @@ -3325,6 +3379,10 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, /* could be a legacy cable, try doing hvdcp */ try_rerun_apsd_for_hvdcp(chg); + /* enable HDC and ICL irq for QC2/3 charger */ + if (qc_charger) + vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); + /* * HVDCP detection timeout done * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. @@ -3575,6 +3633,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0); vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0); + vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); + vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0); /* reset votes from vbus_cc_short */ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, @@ -4257,6 +4317,15 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE", + VOTE_SET_ANY, + smblib_usb_irq_enable_vote_callback, + chg); + if (IS_ERR(chg->usb_irq_enable_votable)) { + rc = PTR_ERR(chg->usb_irq_enable_votable); + return rc; + } + return rc; } diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index de236164e6b2..32a1c29bb376 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -32,10 +32,12 @@ enum print_reason { #define USER_VOTER "USER_VOTER" #define PD_VOTER "PD_VOTER" #define DCP_VOTER "DCP_VOTER" +#define QC_VOTER "QC_VOTER" #define PL_USBIN_USBIN_VOTER "PL_USBIN_USBIN_VOTER" #define USB_PSY_VOTER "USB_PSY_VOTER" #define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER" #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" +#define PL_QNOVO_VOTER "PL_QNOVO_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define USBIN_V_VOTER "USBIN_V_VOTER" #define CHG_STATE_VOTER "CHG_STATE_VOTER" @@ -272,6 +274,7 @@ struct smb_charger { struct votable *hvdcp_enable_votable; struct votable *apsd_disable_votable; struct votable *hvdcp_hw_inov_dis_votable; + struct votable *usb_irq_enable_votable; /* work */ struct work_struct bms_update_work; @@ -455,6 +458,8 @@ int smblib_get_prop_charger_temp_max(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_die_health(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_pd_current_max(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_usb_current_max(struct smb_charger *chg, @@ -475,6 +480,8 @@ int smblib_get_prop_slave_current_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg, + const union power_supply_propval *val); void smblib_suspend_on_debug_battery(struct smb_charger *chg); int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_get_prop_fcc_delta(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 739d80cd8801..c13f5103b02e 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -28,7 +28,7 @@ #include "smb-reg.h" #include "smb-lib.h" #include "storm-watch.h" -#include "pmic-voter.h" +#include <linux/pmic-voter.h> #define SMB138X_DEFAULT_FCC_UA 1000000 #define SMB138X_DEFAULT_ICL_UA 1500000 @@ -96,6 +96,7 @@ struct smb_dt_props { int dc_icl_ua; int chg_temp_max_mdegc; int connector_temp_max_mdegc; + int pl_mode; }; struct smb138x { @@ -161,6 +162,11 @@ static int smb138x_parse_dt(struct smb138x *chip) return -EINVAL; } + rc = of_property_read_u32(node, + "qcom,parallel-mode", &chip->dt.pl_mode); + if (rc < 0) + chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID; + chip->dt.suspend_input = of_property_read_bool(node, "qcom,suspend-input"); @@ -588,7 +594,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, val->strval = "smb138x"; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: - val->intval = POWER_SUPPLY_PL_USBMID_USBMID; + val->intval = chip->dt.pl_mode; break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: val->intval = smb138x_get_prop_connector_health(chip); @@ -1458,6 +1464,15 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } + if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) { + rc = smb138x_init_vbus_regulator(chip); + if (rc < 0) { + pr_err("Couldn't initialize vbus regulator rc=%d\n", + rc); + return rc; + } + } + rc = smb138x_init_parallel_psy(chip); if (rc < 0) { pr_err("Couldn't initialize parallel psy rc=%d\n", rc); @@ -1482,6 +1497,8 @@ cleanup: smblib_deinit(chg); if (chip->parallel_psy) power_supply_unregister(chip->parallel_psy); + if (chg->vbus_vreg && chg->vbus_vreg->rdev) + regulator_unregister(chg->vbus_vreg->rdev); return rc; } diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 117fccf7934a..01a6a83f625d 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -65,7 +65,6 @@ #define PCA9685_MAXCHAN 0x10 #define LED_FULL (1 << 4) -#define MODE1_RESTART (1 << 7) #define MODE1_SLEEP (1 << 4) #define MODE2_INVRT (1 << 4) #define MODE2_OUTDRV (1 << 2) @@ -117,16 +116,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, udelay(500); pca->period_ns = period_ns; - - /* - * If the duty cycle did not change, restart PWM with - * the same duty cycle to period ratio and return. - */ - if (duty_ns == pca->duty_ns) { - regmap_update_bits(pca->regmap, PCA9685_MODE1, - MODE1_RESTART, 0x1); - return 0; - } } else { dev_err(chip->dev, "prescaler not set: period out of bounds!\n"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 88a5c497d5ed..4f9de7fda612 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4705,12 +4705,13 @@ static void regulator_summary_show_subtree(struct seq_file *s, seq_puts(s, "\n"); list_for_each_entry(consumer, &rdev->consumer_list, list) { - if (consumer->dev->class == ®ulator_class) + if (consumer->dev && consumer->dev->class == ®ulator_class) continue; seq_printf(s, "%*s%-*s ", (level + 1) * 3 + 1, "", - 30 - (level + 1) * 3, dev_name(consumer->dev)); + 30 - (level + 1) * 3, + consumer->dev ? dev_name(consumer->dev) : "deviceless"); switch (rdev->desc->type) { case REGULATOR_VOLTAGE: diff --git a/drivers/regulator/cpr3-hmss-regulator.c b/drivers/regulator/cpr3-hmss-regulator.c index 2cbe3914cb68..9a20b6925877 100644 --- a/drivers/regulator/cpr3-hmss-regulator.c +++ b/drivers/regulator/cpr3-hmss-regulator.c @@ -87,8 +87,9 @@ struct cpr3_msm8996_hmss_fuses { /* * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0. * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1. + * Fuse combos 16 - 23 map to CPR fusing revision 0 - 7 with speed bin fuse = 2. */ -#define CPR3_MSM8996_HMSS_FUSE_COMBO_COUNT 16 +#define CPR3_MSM8996_HMSS_FUSE_COMBO_COUNT 24 /* * Constants which define the name of each fuse corner. Note that no actual diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index 80780bf9f527..5a031f503b51 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -72,8 +72,9 @@ struct cpr3_msm8996_mmss_fuses { /* * Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0. * Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1. + * Fuse combos 16 - 23 map to CPR fusing revision 0 - 7 with speed bin fuse = 2. */ -#define CPR3_MSM8996PRO_MMSS_FUSE_COMBO_COUNT 16 +#define CPR3_MSM8996PRO_MMSS_FUSE_COMBO_COUNT 24 /* Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 */ #define CPR3_MSM8998_MMSS_FUSE_COMBO_COUNT 8 diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 5836751b8203..9bb934ed2a7a 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -748,9 +748,23 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq); */ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) { + struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); + struct rtc_time tm; + ktime_t now; + timer->enabled = 1; + __rtc_read_time(rtc, &tm); + now = rtc_tm_to_ktime(tm); + + /* Skip over expired timers */ + while (next) { + if (next->expires.tv64 >= now.tv64) + break; + next = timerqueue_iterate_next(next); + } + timerqueue_add(&rtc->timerqueue, &timer->node); - if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { + if (!next) { struct rtc_wkalrm alarm; int err; alarm.time = rtc_ktime_to_tm(timer->node.expires); diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index c169a2cd4727..e29cc9fca0bf 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -37,9 +37,11 @@ /* Control register */ #define SUN6I_LOSC_CTRL 0x0000 +#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16) #define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9) #define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8) #define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7) +#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0) #define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7) /* RTC */ @@ -114,13 +116,17 @@ struct sun6i_rtc_dev { void __iomem *base; int irq; unsigned long alarm; + + spinlock_t lock; }; static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id) { struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id; + irqreturn_t ret = IRQ_NONE; u32 val; + spin_lock(&chip->lock); val = readl(chip->base + SUN6I_ALRM_IRQ_STA); if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) { @@ -129,10 +135,11 @@ static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id) rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); - return IRQ_HANDLED; + ret = IRQ_HANDLED; } + spin_unlock(&chip->lock); - return IRQ_NONE; + return ret; } static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip) @@ -140,6 +147,7 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip) u32 alrm_val = 0; u32 alrm_irq_val = 0; u32 alrm_wake_val = 0; + unsigned long flags; if (to) { alrm_val = SUN6I_ALRM_EN_CNT_EN; @@ -150,9 +158,11 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip) chip->base + SUN6I_ALRM_IRQ_STA); } + spin_lock_irqsave(&chip->lock, flags); writel(alrm_val, chip->base + SUN6I_ALRM_EN); writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN); writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG); + spin_unlock_irqrestore(&chip->lock, flags); } static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) @@ -191,11 +201,15 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm) { struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); + unsigned long flags; u32 alrm_st; u32 alrm_en; + spin_lock_irqsave(&chip->lock, flags); alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN); alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA); + spin_unlock_irqrestore(&chip->lock, flags); + wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN); wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN); rtc_time_to_tm(chip->alarm, &wkalrm->time); @@ -356,6 +370,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev) chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + spin_lock_init(&chip->lock); platform_set_drvdata(pdev, chip); chip->dev = &pdev->dev; @@ -404,6 +419,10 @@ static int sun6i_rtc_probe(struct platform_device *pdev) /* disable alarm wakeup */ writel(0, chip->base + SUN6I_ALARM_CONFIG); + /* switch to the external, more precise, oscillator */ + writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC, + chip->base + SUN6I_LOSC_CTRL); + chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev, &sun6i_rtc_ops, THIS_MODULE); if (IS_ERR(chip->rtc)) { diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 94a8f4ab57bc..ae1dc37e4068 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -892,7 +892,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, dev_info = bdev->bd_disk->private_data; if (!dev_info) return -ENODEV; - dev_sz = dev_info->end - dev_info->start; + dev_sz = dev_info->end - dev_info->start + 1; offset = secnum * 512; addr = (void *) (dev_info->start + offset); *pfn = virt_to_phys(addr) >> PAGE_SHIFT; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 5d06253c2a7a..30e9fbbff051 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -147,11 +147,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) struct qdio_q *q; int i; - for_each_input_queue(irq, q, i) { - if (!references_shared_dsci(irq) && - has_multiple_inq_on_dsci(irq)) - xchg(q->irq_ptr->dsci, 0); + if (!references_shared_dsci(irq) && + has_multiple_inq_on_dsci(irq)) + xchg(irq->dsci, 0); + for_each_input_queue(irq, q, i) { if (q->u.in.queue_start_poll) { /* skip if polling is enabled or already in work */ if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index bc0203f3d243..e415e1c58eb5 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -413,16 +413,23 @@ static int aac_src_check_health(struct aac_dev *dev) u32 status = src_readl(dev, MUnit.OMR); /* + * Check to see if the board panic'd. + */ + if (unlikely(status & KERNEL_PANIC)) + goto err_blink; + + /* * Check to see if the board failed any self tests. */ if (unlikely(status & SELF_TEST_FAILED)) - return -1; + goto err_out; /* - * Check to see if the board panic'd. + * Check to see if the board failed any self tests. */ - if (unlikely(status & KERNEL_PANIC)) - return (status >> 16) & 0xFF; + if (unlikely(status & MONITOR_PANIC)) + goto err_out; + /* * Wait for the adapter to be up and running. */ @@ -432,6 +439,12 @@ static int aac_src_check_health(struct aac_dev *dev) * Everything is OK */ return 0; + +err_out: + return -1; + +err_blink: + return (status > 16) & 0xFF; } /** diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 33ec4fa39ccb..f224cdb2fce4 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1182,6 +1182,7 @@ struct lpfc_mbx_wq_create { #define lpfc_mbx_wq_create_page_size_SHIFT 0 #define lpfc_mbx_wq_create_page_size_MASK 0x000000FF #define lpfc_mbx_wq_create_page_size_WORD word1 +#define LPFC_WQ_PAGE_SIZE_4096 0x1 #define lpfc_mbx_wq_create_wqe_size_SHIFT 8 #define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F #define lpfc_mbx_wq_create_wqe_size_WORD word1 @@ -1253,6 +1254,7 @@ struct rq_context { #define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */ #define lpfc_rq_context_page_size_MASK 0x000000FF #define lpfc_rq_context_page_size_WORD word0 +#define LPFC_RQ_PAGE_SIZE_4096 0x1 uint32_t reserved1; uint32_t word2; #define lpfc_rq_context_cq_id_SHIFT 16 diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 92dfd6a5178c..f5aeda8f014f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13475,7 +13475,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, LPFC_WQ_WQE_SIZE_128); bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, - (PAGE_SIZE/SLI4_PAGE_SIZE)); + LPFC_WQ_PAGE_SIZE_4096); page = wq_create->u.request_1.page; break; } @@ -13501,8 +13501,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, LPFC_WQ_WQE_SIZE_128); break; } - bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, - (PAGE_SIZE/SLI4_PAGE_SIZE)); + bf_set(lpfc_mbx_wq_create_page_size, + &wq_create->u.request_1, + LPFC_WQ_PAGE_SIZE_4096); page = wq_create->u.request_1.page; break; default: @@ -13688,7 +13689,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, LPFC_RQE_SIZE_8); bf_set(lpfc_rq_context_page_size, &rq_create->u.request.context, - (PAGE_SIZE/SLI4_PAGE_SIZE)); + LPFC_RQ_PAGE_SIZE_4096); } else { switch (hrq->entry_count) { default: diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 9c780740fb82..e712fe745955 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -737,8 +737,8 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf mv_dprintk("device %016llx not ready.\n", SAS_ADDR(dev->sas_addr)); - rc = SAS_PHY_DOWN; - return rc; + rc = SAS_PHY_DOWN; + return rc; } tei.port = dev->port->lldd_port; if (tei.port && !tei.port->port_attached && !tmf) { diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index e7649ed3f667..4d655b568269 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -289,20 +289,6 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) } EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); -static struct scsi_device *get_sdev_from_queue(struct request_queue *q) -{ - struct scsi_device *sdev; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - sdev = NULL; - spin_unlock_irqrestore(q->queue_lock, flags); - - return sdev; -} - /* * scsi_dh_activate - activate the path associated with the scsi_device * corresponding to the given request queue. @@ -321,7 +307,7 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) struct scsi_device *sdev; int err = SCSI_DH_NOSYS; - sdev = get_sdev_from_queue(q); + sdev = scsi_device_from_queue(q); if (!sdev) { if (fn) fn(data, err); @@ -368,7 +354,7 @@ int scsi_dh_set_params(struct request_queue *q, const char *params) struct scsi_device *sdev; int err = -SCSI_DH_NOSYS; - sdev = get_sdev_from_queue(q); + sdev = scsi_device_from_queue(q); if (!sdev) return err; @@ -391,7 +377,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name) struct scsi_device_handler *scsi_dh; int err = 0; - sdev = get_sdev_from_queue(q); + sdev = scsi_device_from_queue(q); if (!sdev) return -ENODEV; @@ -429,7 +415,7 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) struct scsi_device *sdev; const char *handler_name = NULL; - sdev = get_sdev_from_queue(q); + sdev = scsi_device_from_queue(q); if (!sdev) return NULL; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index cf5b99e1f12b..887045ae5d10 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1120,7 +1120,8 @@ int scsi_init_io(struct scsi_cmnd *cmd) bool is_mq = (rq->mq_ctx != NULL); int error; - BUG_ON(!rq->nr_phys_segments); + if (WARN_ON_ONCE(!rq->nr_phys_segments)) + return -EINVAL; error = scsi_init_sgtable(rq, &cmd->sdb); if (error) @@ -2214,6 +2215,29 @@ void scsi_mq_destroy_tags(struct Scsi_Host *shost) blk_mq_free_tag_set(&shost->tag_set); } +/** + * scsi_device_from_queue - return sdev associated with a request_queue + * @q: The request queue to return the sdev from + * + * Return the sdev associated with a request queue or NULL if the + * request_queue does not reference a SCSI device. + */ +struct scsi_device *scsi_device_from_queue(struct request_queue *q) +{ + struct scsi_device *sdev = NULL; + + if (q->mq_ops) { + if (q->mq_ops == &scsi_mq_ops) + sdev = q->queuedata; + } else if (q->request_fn == scsi_request_fn) + sdev = q->queuedata; + if (!sdev || !get_device(&sdev->sdev_gendev)) + sdev = NULL; + + return sdev; +} +EXPORT_SYMBOL_GPL(scsi_device_from_queue); + /* * Function: scsi_block_requests() * diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index e52090b18327..93a523b42d3d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1760,6 +1760,10 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) return res; iov_iter_truncate(&i, hp->dxfer_len); + if (!iov_iter_count(&i)) { + kfree(iov); + return -EINVAL; + } res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC); kfree(iov); diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 0f636cc4c809..cd5c1c060481 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -135,6 +135,8 @@ struct hv_fc_wwn_packet { #define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000 #define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000 +#define SP_UNTAGGED ((unsigned char) ~0) +#define SRB_SIMPLE_TAG_REQUEST 0x20 /* * Platform neutral description of a scsi request - @@ -354,6 +356,7 @@ enum storvsc_request_type { #define SRB_STATUS_SUCCESS 0x01 #define SRB_STATUS_ABORTED 0x02 #define SRB_STATUS_ERROR 0x04 +#define SRB_STATUS_DATA_OVERRUN 0x12 #define SRB_STATUS(status) \ (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) @@ -864,6 +867,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, switch (SRB_STATUS(vm_srb->srb_status)) { case SRB_STATUS_ERROR: /* + * Let upper layer deal with error when + * sense message is present. + */ + + if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) + break; + /* * If there is an error; offline the device since all * error recovery strategies would have already been * deployed on the host side. However, if the command @@ -927,6 +937,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) struct hv_host_device *host_dev = shost_priv(scmnd->device->host); struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; + u32 data_transfer_length; struct Scsi_Host *host; struct storvsc_device *stor_dev; struct hv_device *dev = host_dev->dev; @@ -937,6 +948,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) host = stor_dev->host; vm_srb = &cmd_request->vstor_packet.vm_srb; + data_transfer_length = vm_srb->data_transfer_length; scmnd->result = vm_srb->scsi_status; @@ -947,13 +959,20 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) &sense_hdr); } - if (vm_srb->srb_status != SRB_STATUS_SUCCESS) + if (vm_srb->srb_status != SRB_STATUS_SUCCESS) { storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc, sense_hdr.ascq); + /* + * The Windows driver set data_transfer_length on + * SRB_STATUS_DATA_OVERRUN. On other errors, this value + * is untouched. In these cases we set it to 0. + */ + if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN) + data_transfer_length = 0; + } scsi_set_resid(scmnd, - cmd_request->payload->range.len - - vm_srb->data_transfer_length); + cmd_request->payload->range.len - data_transfer_length); scmnd->scsi_done(scmnd); @@ -1409,6 +1428,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + if (scmnd->device->tagged_supported) { + vm_srb->win8_extension.srb_flags |= + (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE); + vm_srb->win8_extension.queue_tag = SP_UNTAGGED; + vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST; + } + /* Build the SRB */ switch (scmnd->sc_data_direction) { case DMA_TO_DEVICE: diff --git a/drivers/soc/qcom/mpm-of.c b/drivers/soc/qcom/mpm-of.c index 93f2de8a59dd..77c50528be4b 100644 --- a/drivers/soc/qcom/mpm-of.c +++ b/drivers/soc/qcom/mpm-of.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -129,18 +129,6 @@ static uint32_t *msm_mpm_falling_edge; static uint32_t *msm_mpm_rising_edge; static uint32_t *msm_mpm_polarity; -enum { - MSM_MPM_DEBUG_NON_DETECTABLE_IRQ = BIT(0), - MSM_MPM_DEBUG_PENDING_IRQ = BIT(1), - MSM_MPM_DEBUG_WRITE = BIT(2), - MSM_MPM_DEBUG_NON_DETECTABLE_IRQ_IDLE = BIT(3), -}; - -static int msm_mpm_debug_mask = 1; -module_param_named( - debug_mask, msm_mpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP -); - enum mpm_state { MSM_MPM_GIC_IRQ_MAPPING_DONE = BIT(0), MSM_MPM_GPIO_IRQ_MAPPING_DONE = BIT(1), @@ -174,9 +162,6 @@ static inline void msm_mpm_write( unsigned int offset = reg * MSM_MPM_REG_WIDTH + subreg_index + 2; __raw_writel(value, msm_mpm_dev_data.mpm_request_reg_base + offset * 4); - if (MSM_MPM_DEBUG_WRITE & msm_mpm_debug_mask) - pr_info("%s: reg %u.%u: 0x%08x\n", - __func__, reg, subreg_index, value); } static inline void msm_mpm_send_interrupt(void) @@ -513,37 +498,19 @@ int msm_mpm_set_pin_type(unsigned int pin, unsigned int flow_type) static bool msm_mpm_interrupts_detectable(int d, bool from_idle) { unsigned long *irq_bitmap; - bool debug_mask, ret = false; + bool ret = false; struct mpm_irqs *unlisted = &unlisted_irqs[d]; if (!msm_mpm_is_initialized()) return false; - if (from_idle) { + if (from_idle) irq_bitmap = unlisted->enabled_irqs; - debug_mask = msm_mpm_debug_mask & - MSM_MPM_DEBUG_NON_DETECTABLE_IRQ_IDLE; - } else { + else irq_bitmap = unlisted->wakeup_irqs; - debug_mask = msm_mpm_debug_mask & - MSM_MPM_DEBUG_NON_DETECTABLE_IRQ; - } ret = (bool) bitmap_empty(irq_bitmap, unlisted->size); - if (debug_mask && !ret) { - int i = 0; - i = find_first_bit(irq_bitmap, unlisted->size); - pr_info("%s(): %s preventing system sleep modes during %s\n", - __func__, unlisted->domain_name, - from_idle ? "idle" : "suspend"); - - while (i < unlisted->size) { - pr_info("\thwirq: %d\n", i); - i = find_next_bit(irq_bitmap, unlisted->size, i + 1); - } - } - return ret; } @@ -601,10 +568,6 @@ void msm_mpm_exit_sleep(bool from_idle) pending = msm_mpm_read(MSM_MPM_REG_STATUS, i); pending &= enabled_intr[i]; - if (MSM_MPM_DEBUG_PENDING_IRQ & msm_mpm_debug_mask) - pr_info("%s: enabled_intr.%d pending.%d: 0x%08x 0x%08lx\n", - __func__, i, i, enabled_intr[i], pending); - k = find_first_bit(&pending, 32); while (k < 32) { unsigned int mpm_irq = 32 * i + k; diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c index 10fb4cc8ebff..aafe82f59b9a 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is Mree software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1349,6 +1349,7 @@ static void unregister_adhoc(struct msm_bus_client_handle *cl) cl->first_hop, cl->active_only); commit_data(); msm_bus_dbg_remove_client(cl); + kfree(cl->name); kfree(cl); exit_unregister_client: rt_mutex_unlock(&msm_bus_adhoc_lock); diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c index 06657a666f2e..305f31f31bf8 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c @@ -531,7 +531,7 @@ static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node) { struct msm_bus_node_device_type *bus_node = NULL; int i; - int ret; + int ret = 0; long rounded_rate; if (!node || (!to_msm_bus_node(node->node_info->bus_device))) { diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 21e9f17e6a7e..6e5ddc4a3a7d 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -465,6 +465,8 @@ static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr, if (region == NULL) { pil_err(priv->desc, "Failed to allocate relocatable region of size %zx\n", size); + priv->region_start = 0; + priv->region_end = 0; return -ENOMEM; } @@ -920,7 +922,8 @@ out: &desc->attrs); priv->region = NULL; } - pil_clear_segment(desc); + if (desc->clear_fw_region && priv->region_start) + pil_clear_segment(desc); pil_release_mmap(desc); } return ret; diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h index 802abe26a960..9521cf726069 100644 --- a/drivers/soc/qcom/peripheral-loader.h +++ b/drivers/soc/qcom/peripheral-loader.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,7 @@ struct pil_priv; * This defaults to iounmap if not specified. * @shutdown_fail: Set if PIL op for shutting down subsystem fails. * @modem_ssr: true if modem is restarting, false if booting for first time. + * @clear_fw_region: Clear fw region on failure in loading. * @subsys_vmid: memprot id for the subsystem. */ struct pil_desc { @@ -56,6 +57,7 @@ struct pil_desc { void *map_data; bool shutdown_fail; bool modem_ssr; + bool clear_fw_region; u32 subsys_vmid; }; diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c index a39c2b6aa672..34228f072b28 100644 --- a/drivers/soc/qcom/pil-q6v5.c +++ b/drivers/soc/qcom/pil-q6v5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -588,6 +588,7 @@ struct q6v5_data *pil_q6v5_init(struct platform_device *pdev) if (ret) return ERR_PTR(ret); + desc->clear_fw_region = false; desc->dev = &pdev->dev; drv->qdsp6v5_2_0 = of_device_is_compatible(pdev->dev.of_node, diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 20f406b9a2f7..f2784dedbc7a 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -716,51 +716,6 @@ int msm_rpm_smd_buffer_request(struct msm_rpm_request *cdata, return 0; } -static void msm_rpm_print_sleep_buffer(struct slp_buf *s) -{ - char buf[DEBUG_PRINT_BUFFER_SIZE] = {0}; - int pos; - int buflen = DEBUG_PRINT_BUFFER_SIZE; - char ch[5] = {0}; - struct kvp *e; - uint32_t type; - unsigned int id; - - if (!s) - return; - - if (!s->valid) - return; - - type = get_rsc_type(s->buf); - id = get_rsc_id(s->buf); - - memcpy(ch, &type, sizeof(u32)); - - pos = scnprintf(buf, buflen, - "Sleep request type = 0x%08x(%s)", - type, ch); - pos += scnprintf(buf + pos, buflen - pos, " id = 0%x", - id); - for_each_kvp(s->buf, e) { - uint32_t i; - char *data = get_data(e); - - memcpy(ch, &e->k, sizeof(u32)); - - pos += scnprintf(buf + pos, buflen - pos, - "\n\t\tkey = 0x%08x(%s)", - e->k, ch); - pos += scnprintf(buf + pos, buflen - pos, - " sz= %d data =", e->s); - - for (i = 0; i < e->s; i++) - pos += scnprintf(buf + pos, buflen - pos, - " 0x%02X", data[i]); - } - pos += scnprintf(buf + pos, buflen - pos, "\n"); - printk(buf); -} static struct msm_rpm_driver_data msm_rpm_data = { .smd_open = COMPLETION_INITIALIZER(msm_rpm_data.smd_open), @@ -821,9 +776,6 @@ static int msm_rpm_flush_requests(bool print) if (!s->valid) continue; - if (print) - msm_rpm_print_sleep_buffer(s); - set_msg_id(s->buf, msm_rpm_get_next_msg_id()); if (!glink_enabled) diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 0d6c1d62c732..5ac2a58899f4 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -375,6 +375,7 @@ int get_service_location(char *client_name, char *service_name, if (!pqw) { rc = -ENOMEM; pr_err("Allocation failed\n"); + kfree(pqcd); goto err; } pqw->notifier = locator_nb; diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index ebea5b7726e4..fa916ac5ade4 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -99,11 +99,12 @@ struct ind_req_resp { */ struct qmi_client_info { int instance_id; - int subsys_state; + enum pd_subsys_state subsys_state; struct work_struct svc_arrive; struct work_struct svc_exit; struct work_struct svc_rcv_msg; struct work_struct ind_ack; + struct work_struct qmi_handle_free; struct workqueue_struct *svc_event_wq; struct qmi_handle *clnt_handle; struct notifier_block notifier; @@ -123,6 +124,18 @@ static void root_service_clnt_recv_msg(struct work_struct *work); static void root_service_service_arrive(struct work_struct *work); static void root_service_exit_work(struct work_struct *work); +static void free_qmi_handle(struct work_struct *work) +{ + struct qmi_client_info *data = container_of(work, + struct qmi_client_info, qmi_handle_free); + + mutex_lock(&qmi_client_release_lock); + data->service_connected = false; + qmi_handle_destroy(data->clnt_handle); + data->clnt_handle = NULL; + mutex_unlock(&qmi_client_release_lock); +} + static struct service_notif_info *_find_service_info(const char *service_path) { struct service_notif_info *service_notif; @@ -426,11 +439,7 @@ static void root_service_service_exit(struct qmi_client_info *data, * Destroy client handle and try connecting when * service comes up again. */ - mutex_lock(&qmi_client_release_lock); - data->service_connected = false; - qmi_handle_destroy(data->clnt_handle); - data->clnt_handle = NULL; - mutex_unlock(&qmi_client_release_lock); + queue_work(data->svc_event_wq, &data->qmi_handle_free); } static void root_service_exit_work(struct work_struct *work) @@ -486,7 +495,7 @@ static int ssr_event_notify(struct notifier_block *this, info->subsys_state = ROOT_PD_SHUTDOWN; break; } - queue_work(info->svc_event_wq, &info->svc_exit); + root_service_service_exit(info, info->subsys_state); break; default: break; @@ -561,6 +570,7 @@ static void *add_service_notif(const char *service_path, int instance_id, INIT_WORK(&qmi_data->svc_exit, root_service_exit_work); INIT_WORK(&qmi_data->svc_rcv_msg, root_service_clnt_recv_msg); INIT_WORK(&qmi_data->ind_ack, send_ind_ack); + INIT_WORK(&qmi_data->qmi_handle_free, free_qmi_handle); *curr_state = service_notif->curr_state = SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01; diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 07610877f140..457361ba5ff8 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -2241,7 +2241,7 @@ static ssize_t spcom_device_write(struct file *filp, } /** - * spcom_device_read() - handle channel file write() from user space. + * spcom_device_read() - handle channel file read() from user space. * * @filp: file pointer * @@ -2267,6 +2267,16 @@ static ssize_t spcom_device_read(struct file *filp, char __user *user_buff, ch = filp->private_data; + if (ch == NULL) { + pr_err("invalid ch pointer, file [%s].\n", name); + return -EINVAL; + } + + if (!spcom_is_channel_open(ch)) { + pr_err("ch is not open, file [%s].\n", name); + return -EINVAL; + } + buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; @@ -2354,6 +2364,10 @@ static unsigned int spcom_device_poll(struct file *filp, done = (spcom_dev->link_state == GLINK_LINK_STATE_UP); break; case SPCOM_POLL_CH_CONNECT: + if (ch == NULL) { + pr_err("invalid ch pointer, file [%s].\n", name); + return -EINVAL; + } pr_debug("ch [%s] SPCOM_POLL_CH_CONNECT.\n", name); if (wait) { reinit_completion(&ch->connect); diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index c6531de48f65..991bce363740 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -1034,6 +1034,7 @@ static int pil_tz_driver_probe(struct platform_device *pdev) d->desc.ops = &pil_ops_trusted; d->desc.proxy_timeout = PROXY_TIMEOUT_MS; + d->desc.clear_fw_region = true; rc = of_property_read_u32(pdev->dev.of_node, "qcom,proxy-timeout-ms", &proxy_timeout); diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c index 63bc3961de3b..e72663bd2138 100644 --- a/drivers/soundwire/swr-wcd-ctrl.c +++ b/drivers/soundwire/swr-wcd-ctrl.c @@ -224,6 +224,12 @@ static struct dentry *debugfs_poke; static struct dentry *debugfs_reg_dump; static unsigned int read_data; + +static bool swrm_is_msm_variant(int val) +{ + return (val == SWRM_VERSION_1_3); +} + static int swrm_debug_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -514,8 +520,17 @@ static int swrm_cmd_fifo_wr_cmd(struct swr_mstr_ctrl *swrm, u8 cmd_data, __func__, val, ret); goto err; } - if (cmd_id == 0xF) - wait_for_completion_timeout(&swrm->broadcast, (2 * HZ/10)); + if (cmd_id == 0xF) { + /* + * sleep for 10ms for MSM soundwire variant to allow broadcast + * command to complete. + */ + if (swrm_is_msm_variant(swrm->version)) + usleep_range(10000, 10100); + else + wait_for_completion_timeout(&swrm->broadcast, + (2 * HZ/10)); + } err: return ret; } @@ -1472,6 +1487,7 @@ static int swrm_probe(struct platform_device *pdev) mutex_unlock(&swrm->mlock); goto err_mstr_fail; } + swrm->version = swrm->read(swrm->handle, SWRM_COMP_HW_VERSION); /* Enumerate slave devices */ list_for_each_entry_safe(swr_dev, safe, &swrm->master.devices, diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h index 8992318cdbd3..b7a3edac3e00 100755 --- a/drivers/soundwire/swr-wcd-ctrl.h +++ b/drivers/soundwire/swr-wcd-ctrl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,6 +23,10 @@ #define SWR_MSTR_PORT_LEN 8 /* Number of master ports */ +#define SWRM_VERSION_1_0 0x01010000 +#define SWRM_VERSION_1_2 0x01030000 +#define SWRM_VERSION_1_3 0x01040000 + enum { SWR_MSTR_PAUSE, SWR_MSTR_RESUME, @@ -88,6 +92,7 @@ struct swr_mstr_ctrl { int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq, void *data), void *swr_handle, int type); int irq; + int version; int num_enum_slaves; int slave_status; struct swr_mstr_port *mstr_port; diff --git a/drivers/soundwire/swrm_registers.h b/drivers/soundwire/swrm_registers.h index c6923f301f9f..50c3ecfdd47d 100755 --- a/drivers/soundwire/swrm_registers.h +++ b/drivers/soundwire/swrm_registers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,7 @@ #define SWRM_BASE_ADDRESS 0x00 +#define SWRM_COMP_HW_VERSION SWRM_BASE_ADDRESS #define SWRM_COMP_CFG_ADDR (SWRM_BASE_ADDRESS+0x00000004) #define SWRM_COMP_CFG_RMSK 0x3 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_BMSK 0x2 diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 03b2b8a38991..2ad4cc7a4785 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -123,9 +123,11 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, gfp_t gfp_mask = low_order_gfp_flags; if (order) gfp_mask = high_order_gfp_flags; + page = alloc_pages(gfp_mask, order); - ion_pages_sync_for_device(dev, page, PAGE_SIZE << order, - DMA_BIDIRECTIONAL); + if (page) + ion_pages_sync_for_device(dev, page, PAGE_SIZE << order, + DMA_BIDIRECTIONAL); } if (!page) return 0; diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 110b8c0b6cd7..0f2fe34e14c2 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -1405,6 +1405,9 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe) ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); } + if (!ptr) + return _FAIL; + memcpy(ptr, pattrib->dst, ETH_ALEN); memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c index 4ff530155187..04ac23cc47a8 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ b/drivers/staging/rtl8712/rtl871x_recv.c @@ -641,11 +641,16 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe) /* append rx status for mp test packets */ ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24); + if (!ptr) + return _FAIL; memcpy(ptr, get_rxmem(precvframe), 24); ptr += 24; - } else + } else { ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); + if (!ptr) + return _FAIL; + } memcpy(ptr, pattrib->dst, ETH_ALEN); memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index bd810c109277..6ed80b05d674 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3436,7 +3436,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, if ((tpg->tpg_attrib.generate_node_acls == 0) && (tpg->tpg_attrib.demo_mode_discovery == 0) && - (!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg, + (!target_tpg_has_node_acl(&tpg->tpg_se_tpg, cmd->conn->sess->sess_ops->InitiatorName))) { continue; } diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 356c80fbb304..bb6a6c35324a 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -77,12 +77,16 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) &deve->read_bytes); se_lun = rcu_dereference(deve->se_lun); + + if (!percpu_ref_tryget_live(&se_lun->lun_ref)) { + se_lun = NULL; + goto out_unlock; + } + se_cmd->se_lun = rcu_dereference(deve->se_lun); se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; - - percpu_ref_get(&se_lun->lun_ref); se_cmd->lun_ref_active = true; if ((se_cmd->data_direction == DMA_TO_DEVICE) && @@ -96,6 +100,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) goto ref_dev; } } +out_unlock: rcu_read_unlock(); if (!se_lun) { @@ -826,6 +831,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun = &dev->xcopy_lun; rcu_assign_pointer(xcopy_lun->lun_se_dev, dev); init_completion(&xcopy_lun->lun_ref_comp); + init_completion(&xcopy_lun->lun_shutdown_comp); INIT_LIST_HEAD(&xcopy_lun->lun_deve_list); INIT_LIST_HEAD(&xcopy_lun->lun_dev_link); mutex_init(&xcopy_lun->lun_tg_pt_md_mutex); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5fb9dd7f08bb..2794c6ec5c3c 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -75,9 +75,21 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( unsigned char *initiatorname) { struct se_node_acl *acl; - + /* + * Obtain se_node_acl->acl_kref using fabric driver provided + * initiatorname[] during node acl endpoint lookup driven by + * new se_session login. + * + * The reference is held until se_session shutdown -> release + * occurs via fabric driver invoked transport_deregister_session() + * or transport_free_session() code. + */ mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); + if (acl) { + if (!kref_get_unless_zero(&acl->acl_kref)) + acl = NULL; + } mutex_unlock(&tpg->acl_node_mutex); return acl; @@ -232,6 +244,25 @@ static void target_add_node_acl(struct se_node_acl *acl) acl->initiatorname); } +bool target_tpg_has_node_acl(struct se_portal_group *tpg, + const char *initiatorname) +{ + struct se_node_acl *acl; + bool found = false; + + mutex_lock(&tpg->acl_node_mutex); + list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { + if (!strcmp(acl->initiatorname, initiatorname)) { + found = true; + break; + } + } + mutex_unlock(&tpg->acl_node_mutex); + + return found; +} +EXPORT_SYMBOL(target_tpg_has_node_acl); + struct se_node_acl *core_tpg_check_initiator_node_acl( struct se_portal_group *tpg, unsigned char *initiatorname) @@ -248,6 +279,15 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( acl = target_alloc_node_acl(tpg, initiatorname); if (!acl) return NULL; + /* + * When allocating a dynamically generated node_acl, go ahead + * and take the extra kref now before returning to the fabric + * driver caller. + * + * Note this reference will be released at session shutdown + * time within transport_free_session() code. + */ + kref_get(&acl->acl_kref); acl->dynamic_node_acl = 1; /* @@ -499,7 +539,7 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref) { struct se_lun *lun = container_of(ref, struct se_lun, lun_ref); - complete(&lun->lun_ref_comp); + complete(&lun->lun_shutdown_comp); } int core_tpg_register( @@ -626,6 +666,7 @@ struct se_lun *core_tpg_alloc_lun( lun->lun_link_magic = SE_LUN_LINK_MAGIC; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_ref_comp); + init_completion(&lun->lun_shutdown_comp); INIT_LIST_HEAD(&lun->lun_deve_list); INIT_LIST_HEAD(&lun->lun_dev_link); atomic_set(&lun->lun_tg_pt_secondary_offline, 0); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index aa517c4fadb9..df2059984e14 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -341,7 +341,6 @@ void __transport_register_session( &buf[0], PR_REG_ISID_LEN); se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]); } - kref_get(&se_nacl->acl_kref); spin_lock_irq(&se_nacl->nacl_sess_lock); /* @@ -424,14 +423,27 @@ static void target_complete_nacl(struct kref *kref) { struct se_node_acl *nacl = container_of(kref, struct se_node_acl, acl_kref); + struct se_portal_group *se_tpg = nacl->se_tpg; - complete(&nacl->acl_free_comp); + if (!nacl->dynamic_stop) { + complete(&nacl->acl_free_comp); + return; + } + + mutex_lock(&se_tpg->acl_node_mutex); + list_del(&nacl->acl_list); + mutex_unlock(&se_tpg->acl_node_mutex); + + core_tpg_wait_for_nacl_pr_ref(nacl); + core_free_device_list_for_node(nacl, se_tpg); + kfree(nacl); } void target_put_nacl(struct se_node_acl *nacl) { kref_put(&nacl->acl_kref, target_complete_nacl); } +EXPORT_SYMBOL(target_put_nacl); void transport_deregister_session_configfs(struct se_session *se_sess) { @@ -464,6 +476,42 @@ EXPORT_SYMBOL(transport_deregister_session_configfs); void transport_free_session(struct se_session *se_sess) { + struct se_node_acl *se_nacl = se_sess->se_node_acl; + + /* + * Drop the se_node_acl->nacl_kref obtained from within + * core_tpg_get_initiator_node_acl(). + */ + if (se_nacl) { + struct se_portal_group *se_tpg = se_nacl->se_tpg; + const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo; + unsigned long flags; + + se_sess->se_node_acl = NULL; + + /* + * Also determine if we need to drop the extra ->cmd_kref if + * it had been previously dynamically generated, and + * the endpoint is not caching dynamic ACLs. + */ + mutex_lock(&se_tpg->acl_node_mutex); + if (se_nacl->dynamic_node_acl && + !se_tfo->tpg_check_demo_mode_cache(se_tpg)) { + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); + if (list_empty(&se_nacl->acl_sess_list)) + se_nacl->dynamic_stop = true; + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); + + if (se_nacl->dynamic_stop) + list_del(&se_nacl->acl_list); + } + mutex_unlock(&se_tpg->acl_node_mutex); + + if (se_nacl->dynamic_stop) + target_put_nacl(se_nacl); + + target_put_nacl(se_nacl); + } if (se_sess->sess_cmd_map) { percpu_ida_destroy(&se_sess->sess_tag_pool); kvfree(se_sess->sess_cmd_map); @@ -475,16 +523,12 @@ EXPORT_SYMBOL(transport_free_session); void transport_deregister_session(struct se_session *se_sess) { struct se_portal_group *se_tpg = se_sess->se_tpg; - const struct target_core_fabric_ops *se_tfo; - struct se_node_acl *se_nacl; unsigned long flags; - bool comp_nacl = true, drop_nacl = false; if (!se_tpg) { transport_free_session(se_sess); return; } - se_tfo = se_tpg->se_tpg_tfo; spin_lock_irqsave(&se_tpg->session_lock, flags); list_del(&se_sess->sess_list); @@ -492,37 +536,16 @@ void transport_deregister_session(struct se_session *se_sess) se_sess->fabric_sess_ptr = NULL; spin_unlock_irqrestore(&se_tpg->session_lock, flags); - /* - * Determine if we need to do extra work for this initiator node's - * struct se_node_acl if it had been previously dynamically generated. - */ - se_nacl = se_sess->se_node_acl; - - mutex_lock(&se_tpg->acl_node_mutex); - if (se_nacl && se_nacl->dynamic_node_acl) { - if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) { - list_del(&se_nacl->acl_list); - se_tpg->num_node_acls--; - drop_nacl = true; - } - } - mutex_unlock(&se_tpg->acl_node_mutex); - - if (drop_nacl) { - core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_free_device_list_for_node(se_nacl, se_tpg); - kfree(se_nacl); - comp_nacl = false; - } pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->get_fabric_name()); /* * If last kref is dropping now for an explicit NodeACL, awake sleeping * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group - * removal context. + * removal context from within transport_free_session() code. + * + * For dynamic ACL, target_put_nacl() uses target_complete_nacl() + * to release all remaining generate_node_acl=1 created ACL resources. */ - if (se_nacl && comp_nacl) - target_put_nacl(se_nacl); transport_free_session(se_sess); } @@ -2657,10 +2680,39 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) } EXPORT_SYMBOL(target_wait_for_sess_cmds); +static void target_lun_confirm(struct percpu_ref *ref) +{ + struct se_lun *lun = container_of(ref, struct se_lun, lun_ref); + + complete(&lun->lun_ref_comp); +} + void transport_clear_lun_ref(struct se_lun *lun) { - percpu_ref_kill(&lun->lun_ref); + /* + * Mark the percpu-ref as DEAD, switch to atomic_t mode, drop + * the initial reference and schedule confirm kill to be + * executed after one full RCU grace period has completed. + */ + percpu_ref_kill_and_confirm(&lun->lun_ref, target_lun_confirm); + /* + * The first completion waits for percpu_ref_switch_to_atomic_rcu() + * to call target_lun_confirm after lun->lun_ref has been marked + * as __PERCPU_REF_DEAD on all CPUs, and switches to atomic_t + * mode so that percpu_ref_tryget_live() lookup of lun->lun_ref + * fails for all new incoming I/O. + */ wait_for_completion(&lun->lun_ref_comp); + /* + * The second completion waits for percpu_ref_put_many() to + * invoke ->release() after lun->lun_ref has switched to + * atomic_t mode, and lun->lun_ref.count has reached zero. + * + * At this point all target-core lun->lun_ref references have + * been dropped via transport_lun_remove_cmd(), and it's safe + * to proceed with the remaining LUN shutdown. + */ + wait_for_completion(&lun->lun_shutdown_comp); } static bool diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 644ddb841d9f..6d1e2f746ab4 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -114,7 +114,7 @@ #define DEFAULT_TX_BUF_COUNT 3 struct n_hdlc_buf { - struct n_hdlc_buf *link; + struct list_head list_item; int count; char buf[1]; }; @@ -122,8 +122,7 @@ struct n_hdlc_buf { #define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe) struct n_hdlc_buf_list { - struct n_hdlc_buf *head; - struct n_hdlc_buf *tail; + struct list_head list; int count; spinlock_t spinlock; }; @@ -136,7 +135,6 @@ struct n_hdlc_buf_list { * @backup_tty - TTY to use if tty gets closed * @tbusy - reentrancy flag for tx wakeup code * @woke_up - FIXME: describe this field - * @tbuf - currently transmitting tx buffer * @tx_buf_list - list of pending transmit frame buffers * @rx_buf_list - list of received frame buffers * @tx_free_buf_list - list unused transmit frame buffers @@ -149,7 +147,6 @@ struct n_hdlc { struct tty_struct *backup_tty; int tbusy; int woke_up; - struct n_hdlc_buf *tbuf; struct n_hdlc_buf_list tx_buf_list; struct n_hdlc_buf_list rx_buf_list; struct n_hdlc_buf_list tx_free_buf_list; @@ -159,7 +156,8 @@ struct n_hdlc { /* * HDLC buffer list manipulation functions */ -static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list); +static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list, + struct n_hdlc_buf *buf); static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, struct n_hdlc_buf *buf); static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); @@ -209,16 +207,9 @@ static void flush_tx_queue(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); struct n_hdlc_buf *buf; - unsigned long flags; while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list))) n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf); - spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); - if (n_hdlc->tbuf) { - n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf); - n_hdlc->tbuf = NULL; - } - spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); } static struct tty_ldisc_ops n_hdlc_ldisc = { @@ -284,7 +275,6 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc) } else break; } - kfree(n_hdlc->tbuf); kfree(n_hdlc); } /* end of n_hdlc_release() */ @@ -403,13 +393,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) n_hdlc->woke_up = 0; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); - /* get current transmit buffer or get new transmit */ - /* buffer from list of pending transmit buffers */ - - tbuf = n_hdlc->tbuf; - if (!tbuf) - tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); - + tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)sending frame %p, count=%d\n", @@ -421,7 +405,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* rollback was possible and has been done */ if (actual == -ERESTARTSYS) { - n_hdlc->tbuf = tbuf; + n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf); break; } /* if transmit error, throw frame away by */ @@ -436,10 +420,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* free current transmit buffer */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); - - /* this tx buffer is done */ - n_hdlc->tbuf = NULL; - + /* wait up sleeping writers */ wake_up_interruptible(&tty->write_wait); @@ -449,10 +430,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p pending\n", __FILE__,__LINE__,tbuf); - - /* buffer not accepted by driver */ - /* set this buffer as pending buffer */ - n_hdlc->tbuf = tbuf; + + /* + * the buffer was not accepted by driver, + * return it back into tx queue + */ + n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf); break; } } @@ -750,7 +733,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, int error = 0; int count; unsigned long flags; - + struct n_hdlc_buf *buf = NULL; + if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_ioctl() called %d\n", __FILE__,__LINE__,cmd); @@ -764,8 +748,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, /* report count of read data available */ /* in next available frame (if any) */ spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags); - if (n_hdlc->rx_buf_list.head) - count = n_hdlc->rx_buf_list.head->count; + buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list, + struct n_hdlc_buf, list_item); + if (buf) + count = buf->count; else count = 0; spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); @@ -777,8 +763,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, count = tty_chars_in_buffer(tty); /* add size of next output frame in queue */ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags); - if (n_hdlc->tx_buf_list.head) - count += n_hdlc->tx_buf_list.head->count; + buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list, + struct n_hdlc_buf, list_item); + if (buf) + count += buf->count; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags); error = put_user(count, (int __user *)arg); break; @@ -826,14 +814,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, poll_wait(filp, &tty->write_wait, wait); /* set bits for operations that won't block */ - if (n_hdlc->rx_buf_list.head) + if (!list_empty(&n_hdlc->rx_buf_list.list)) mask |= POLLIN | POLLRDNORM; /* readable */ if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= POLLHUP; if (tty_hung_up_p(filp)) mask |= POLLHUP; if (!tty_is_writelocked(tty) && - n_hdlc->tx_free_buf_list.head) + !list_empty(&n_hdlc->tx_free_buf_list.list)) mask |= POLLOUT | POLLWRNORM; /* writable */ } return mask; @@ -853,11 +841,16 @@ static struct n_hdlc *n_hdlc_alloc(void) if (!n_hdlc) return NULL; - n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list); - n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list); - n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); - n_hdlc_buf_list_init(&n_hdlc->tx_buf_list); - + spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock); + spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock); + spin_lock_init(&n_hdlc->rx_buf_list.spinlock); + spin_lock_init(&n_hdlc->tx_buf_list.spinlock); + + INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list); + INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list); + INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list); + INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list); + /* allocate free rx buffer list */ for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) { buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL); @@ -885,63 +878,65 @@ static struct n_hdlc *n_hdlc_alloc(void) } /* end of n_hdlc_alloc() */ /** - * n_hdlc_buf_list_init - initialize specified HDLC buffer list - * @list - pointer to buffer list + * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list + * @buf_list - pointer to the buffer list + * @buf - pointer to the buffer */ -static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list) +static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list, + struct n_hdlc_buf *buf) { - memset(list, 0, sizeof(*list)); - spin_lock_init(&list->spinlock); -} /* end of n_hdlc_buf_list_init() */ + unsigned long flags; + + spin_lock_irqsave(&buf_list->spinlock, flags); + + list_add(&buf->list_item, &buf_list->list); + buf_list->count++; + + spin_unlock_irqrestore(&buf_list->spinlock, flags); +} /** * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list - * @list - pointer to buffer list + * @buf_list - pointer to buffer list * @buf - pointer to buffer */ -static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, +static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list, struct n_hdlc_buf *buf) { unsigned long flags; - spin_lock_irqsave(&list->spinlock,flags); - - buf->link=NULL; - if (list->tail) - list->tail->link = buf; - else - list->head = buf; - list->tail = buf; - (list->count)++; - - spin_unlock_irqrestore(&list->spinlock,flags); - + + spin_lock_irqsave(&buf_list->spinlock, flags); + + list_add_tail(&buf->list_item, &buf_list->list); + buf_list->count++; + + spin_unlock_irqrestore(&buf_list->spinlock, flags); } /* end of n_hdlc_buf_put() */ /** * n_hdlc_buf_get - remove and return an HDLC buffer from list - * @list - pointer to HDLC buffer list + * @buf_list - pointer to HDLC buffer list * * Remove and return an HDLC buffer from the head of the specified HDLC buffer * list. * Returns a pointer to HDLC buffer if available, otherwise %NULL. */ -static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list) +static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) { unsigned long flags; struct n_hdlc_buf *buf; - spin_lock_irqsave(&list->spinlock,flags); - - buf = list->head; + + spin_lock_irqsave(&buf_list->spinlock, flags); + + buf = list_first_entry_or_null(&buf_list->list, + struct n_hdlc_buf, list_item); if (buf) { - list->head = buf->link; - (list->count)--; + list_del(&buf->list_item); + buf_list->count--; } - if (!list->head) - list->tail = NULL; - - spin_unlock_irqrestore(&list->spinlock,flags); + + spin_unlock_irqrestore(&buf_list->spinlock, flags); return buf; - } /* end of n_hdlc_buf_get() */ static char hdlc_banner[] __initdata = diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 029de3f99752..5b24ffd93649 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -2880,6 +2880,8 @@ enum pci_board_num_t { pbn_b0_4_1152000_200, pbn_b0_8_1152000_200, + pbn_b0_4_1250000, + pbn_b0_2_1843200, pbn_b0_4_1843200, @@ -3113,6 +3115,13 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x200, }, + [pbn_b0_4_1250000] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1250000, + .uart_offset = 8, + }, + [pbn_b0_2_1843200] = { .flags = FL_BASE0, .num_ports = 2, @@ -5778,6 +5787,10 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, + /* MKS Tenta SCOM-080x serial cards */ + { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, + { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 8f68acd1d95d..db329230c7ca 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1834,6 +1834,7 @@ static const struct of_device_id msm_match_table[] = { { .compatible = "qcom,msm-uartdm" }, {} }; +MODULE_DEVICE_TABLE(of, msm_match_table); #ifdef CONFIG_PM_SLEEP static int msm_serial_suspend(struct device *dev) diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index f0d5c96ac2e0..cc616d678d42 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -3,7 +3,7 @@ * MSM 7k High speed uart driver * * Copyright (c) 2008 Google Inc. - * Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. * Modified: Nick Pelly <npelly@google.com> * * All source code in this file is licensed under the following license @@ -1436,13 +1436,13 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport) hex_dump_ipc(msm_uport, tx->ipc_tx_ctxt, "Tx", &tx_buf->buf[tx_buf->tail], (u64)src_addr, tx_count); sps_pipe_handle = tx->cons.pipe_handle; - /* Queue transfer request to SPS */ - ret = sps_transfer_one(sps_pipe_handle, src_addr, tx_count, - msm_uport, flags); /* Set 1 second timeout */ mod_timer(&tx->tx_timeout_timer, jiffies + msecs_to_jiffies(MSEC_PER_SEC)); + /* Queue transfer request to SPS */ + ret = sps_transfer_one(sps_pipe_handle, src_addr, tx_count, + msm_uport, flags); MSM_HS_DBG("%s:Enqueue Tx Cmd, ret %d\n", __func__, ret); } diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index ab8308ff7e69..cad76b1cf672 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1030,8 +1030,10 @@ static int s3c64xx_serial_startup(struct uart_port *port) if (ourport->dma) { ret = s3c24xx_serial_request_dma(ourport); if (ret < 0) { - dev_warn(port->dev, "DMA request failed\n"); - return ret; + dev_warn(port->dev, + "DMA request failed, DMA will not be used\n"); + devm_kfree(port->dev, ourport->dma); + ourport->dma = NULL; } } diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 5a048b7b92e8..2949289bb3c5 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -244,7 +244,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) struct ci_hdrc_platform_data pdata = { .name = dev_name(&pdev->dev), .capoffset = DEF_CAPOFFSET, - .flags = CI_HDRC_SET_NON_ZERO_TTHA, }; int ret; const struct of_device_id *of_id; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index a21962c8f513..99ff6df063a7 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -28,23 +28,23 @@ struct dwc3; #define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget)) /* DEPCFG parameter 1 */ -#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0) +#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0) #define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8) #define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9) #define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10) #define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11) #define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13) -#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16) +#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16) #define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24) -#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25) +#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25) #define DWC3_DEPCFG_BULK_BASED (1 << 30) #define DWC3_DEPCFG_FIFO_BASED (1 << 31) /* DEPCFG parameter 0 */ -#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1) -#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3) -#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17) -#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22) +#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1) +#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) (((n) & 0x7ff) << 3) +#define DWC3_DEPCFG_FIFO_NUMBER(n) (((n) & 0x1f) << 17) +#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22) #define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26) /* This applies for core versions earlier than 1.94a */ #define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31) diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 7a64b24b8bf6..a42550950953 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -60,7 +60,7 @@ usb_f_cdev-y := f_cdev.o obj-$(CONFIG_USB_F_CDEV) += usb_f_cdev.o usb_f_qdss-y := f_qdss.o u_qdss.o obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o -usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o +usb_f_qcrndis-y := f_qc_rndis.o rndis.o u_data_ipa.o obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index db7903d19c43..a2a9185a0143 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -989,6 +989,7 @@ static ssize_t audio_source_pcm_show(struct device *dev, struct device *create_function_device(char *name); +#define AUDIO_SOURCE_DEV_NAME_LENGTH 20 static struct usb_function_instance *audio_source_alloc_inst(void) { struct audio_source_instance *fi_audio; @@ -997,6 +998,8 @@ static struct usb_function_instance *audio_source_alloc_inst(void) struct device *dev; void *err_ptr; int err = 0; + char device_name[AUDIO_SOURCE_DEV_NAME_LENGTH]; + static u8 count; fi_audio = kzalloc(sizeof(*fi_audio), GFP_KERNEL); if (!fi_audio) @@ -1014,7 +1017,11 @@ static struct usb_function_instance *audio_source_alloc_inst(void) config_group_init_type_name(&fi_audio->func_inst.group, "", &audio_source_func_type); - dev = create_function_device("f_audio_source"); + + snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH, + "f_audio_source%d", count++); + + dev = create_function_device(device_name); if (IS_ERR(dev)) { err_ptr = dev; diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 4e35ed9654b7..2a7d57cd14cb 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1426,17 +1426,39 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) */ if (!ncm_opts->bound) { mutex_lock(&ncm_opts->lock); + ncm_opts->net = gether_setup_default(); + if (IS_ERR(ncm_opts->net)) { + status = PTR_ERR(ncm_opts->net); + mutex_unlock(&ncm_opts->lock); + goto error; + } gether_set_gadget(ncm_opts->net, cdev->gadget); status = gether_register_netdev(ncm_opts->net); mutex_unlock(&ncm_opts->lock); - if (status) - return status; + if (status) { + free_netdev(ncm_opts->net); + goto error; + } ncm_opts->bound = true; } + + /* export host's Ethernet address in CDC format */ + status = gether_get_host_addr_cdc(ncm_opts->net, ncm->ethaddr, + sizeof(ncm->ethaddr)); + if (status < 12) { /* strlen("01234567890a") */ + ERROR(cdev, "%s: failed to get host eth addr, err %d\n", + __func__, status); + status = -EINVAL; + goto netdev_cleanup; + } + ncm->port.ioport = netdev_priv(ncm_opts->net); + us = usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); - if (IS_ERR(us)) - return PTR_ERR(us); + if (IS_ERR(us)) { + status = PTR_ERR(us); + goto netdev_cleanup; + } ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; @@ -1540,7 +1562,10 @@ fail: kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); } +netdev_cleanup: + gether_cleanup(netdev_priv(ncm_opts->net)); +error: ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; @@ -1588,8 +1613,6 @@ static void ncm_free_inst(struct usb_function_instance *f) opts = container_of(f, struct f_ncm_opts, func_inst); if (opts->bound) gether_cleanup(netdev_priv(opts->net)); - else - free_netdev(opts->net); kfree(opts); } @@ -1602,12 +1625,6 @@ static struct usb_function_instance *ncm_alloc_inst(void) return ERR_PTR(-ENOMEM); mutex_init(&opts->lock); opts->func_inst.free_func_inst = ncm_free_inst; - opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) { - struct net_device *net = opts->net; - kfree(opts); - return ERR_CAST(net); - } config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); @@ -1630,6 +1647,8 @@ static void ncm_free(struct usb_function *f) static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ncm *ncm = func_to_ncm(f); + struct f_ncm_opts *opts = container_of(f->fi, struct f_ncm_opts, + func_inst); DBG(c->cdev, "ncm unbind\n"); @@ -1641,13 +1660,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); + + gether_cleanup(netdev_priv(opts->net)); + opts->bound = false; } static struct usb_function *ncm_alloc(struct usb_function_instance *fi) { struct f_ncm *ncm; struct f_ncm_opts *opts; - int status; /* allocate and initialize one new instance */ ncm = kzalloc(sizeof(*ncm), GFP_KERNEL); @@ -1657,20 +1678,9 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_ncm_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; - - /* export host's Ethernet address in CDC format */ - status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr, - sizeof(ncm->ethaddr)); - if (status < 12) { /* strlen("01234567890a") */ - kfree(ncm); - mutex_unlock(&opts->lock); - return ERR_PTR(-EINVAL); - } ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; - spin_lock_init(&ncm->lock); ncm_reset_values(ncm); - ncm->port.ioport = netdev_priv(opts->net); mutex_unlock(&opts->lock); ncm->port.is_fixed = true; ncm->port.supports_multi_frame = true; diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 29263a84bbea..88db253aeef4 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -493,11 +493,7 @@ static void usb_qdss_disconnect_work(struct work_struct *work) NULL, NULL); - status = set_qdss_data_connection( - qdss->gadget, - qdss->port.data, - qdss->port.data->address, - 0); + status = set_qdss_data_connection(qdss, 0); if (status) pr_err("qdss_disconnect error"); } @@ -543,11 +539,7 @@ static void usb_qdss_connect_work(struct work_struct *work) } pr_debug("usb_qdss_connect_work\n"); - status = set_qdss_data_connection( - qdss->gadget, - qdss->port.data, - qdss->port.data->address, - 1); + status = set_qdss_data_connection(qdss, 1); if (status) { pr_err("set_qdss_data_connection error(%d)", status); return; @@ -868,14 +860,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch) if (status) pr_err("%s: uninit_data error\n", __func__); - status = set_qdss_data_connection( - gadget, - qdss->port.data, - qdss->port.data->address, - 0); + status = set_qdss_data_connection(qdss, 0); if (status) pr_err("%s:qdss_disconnect error\n", __func__); - usb_gadget_restart(gadget); } EXPORT_SYMBOL(usb_qdss_close); diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index e3fe8ae03775..cad0f4cc06f9 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -69,6 +69,5 @@ struct usb_qdss_opts { }; int uninit_data(struct usb_ep *ep); -int set_qdss_data_connection(struct usb_gadget *gadget, - struct usb_ep *data_ep, u8 data_addr, int enable); +int set_qdss_data_connection(struct f_qdss *qdss, int enable); #endif diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c index 42a9cda68659..0ef1e2ab34be 100644 --- a/drivers/usb/gadget/function/u_qdss.c +++ b/drivers/usb/gadget/function/u_qdss.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,19 +40,25 @@ static int alloc_sps_req(struct usb_ep *data_ep) } static int init_data(struct usb_ep *ep); -int set_qdss_data_connection(struct usb_gadget *gadget, - struct usb_ep *data_ep, u8 data_addr, int enable) +int set_qdss_data_connection(struct f_qdss *qdss, int enable) { enum usb_ctrl usb_bam_type; int res = 0; int idx; - struct f_qdss *qdss = data_ep->driver_data; - struct usb_qdss_bam_connect_info bam_info = qdss->bam_info; + struct usb_qdss_bam_connect_info bam_info; + struct usb_gadget *gadget; pr_debug("set_qdss_data_connection\n"); + if (!qdss) { + pr_err("%s: qdss ptr is NULL\n", __func__); + return -EINVAL; + } + + gadget = qdss->gadget; usb_bam_type = usb_bam_get_bam_type(gadget->name); + bam_info = qdss->bam_info; /* There is only one qdss pipe, so the pipe number can be set to 0 */ idx = usb_bam_get_connection_idx(usb_bam_type, QDSS_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); @@ -67,14 +73,16 @@ int set_qdss_data_connection(struct usb_gadget *gadget, kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL); if (!bam_info.data_fifo) { pr_err("qdss_data_connection: memory alloc failed\n"); + usb_bam_free_fifos(usb_bam_type, idx); return -ENOMEM; } get_bam2bam_connection_info(usb_bam_type, idx, &bam_info.usb_bam_pipe_idx, NULL, bam_info.data_fifo, NULL); - alloc_sps_req(data_ep); - msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base, + alloc_sps_req(qdss->port.data); + msm_data_fifo_config(qdss->port.data, + bam_info.data_fifo->phys_base, bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx); init_data(qdss->port.data); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 22d067cd5aa3..6610f7a023d3 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1033,6 +1033,8 @@ static int dummy_udc_probe(struct platform_device *pdev) int rc; dum = *((void **)dev_get_platdata(&pdev->dev)); + /* Clear usb_gadget region for new registration to udc-core */ + memzero_explicit(&dum->gadget, sizeof(struct usb_gadget)); dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; dum->gadget.max_speed = USB_SPEED_SUPER; diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index aab5221d6c2e..aac0ce8aeb0b 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1249,6 +1249,12 @@ static const struct usb_gadget_ops fsl_gadget_ops = { .udc_stop = fsl_udc_stop, }; +/* + * Empty complete function used by this driver to fill in the req->complete + * field when creating a request since the complete field is mandatory. + */ +static void fsl_noop_complete(struct usb_ep *ep, struct usb_request *req) { } + /* Set protocol stall on ep0, protocol stall will automatically be cleared on new transaction */ static void ep0stall(struct fsl_udc *udc) @@ -1283,7 +1289,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) req->req.length = 0; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + req->req.complete = fsl_noop_complete; req->dtd_count = 0; ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); @@ -1366,7 +1372,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, req->req.length = 2; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + req->req.complete = fsl_noop_complete; req->dtd_count = 0; ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 34388950f96b..a190c97d11e4 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -111,7 +111,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); /* xhci 1.1 controllers have the HCCPARAMS2 register */ - if (hci_version > 100) { + if (hci_version > 0x100) { temp = readl(&xhci->cap_regs->hcc_params2); xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC %s Force save context capability", diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3f106b428dba..7423645c204c 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -233,9 +233,6 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd_to_bus(xhci->shared_hcd)->skip_resume = true; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; - hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); if (IS_ERR(hcd->usb_phy)) { ret = PTR_ERR(hcd->usb_phy); @@ -254,6 +251,9 @@ static int xhci_plat_probe(struct platform_device *pdev) device_wakeup_enable(&hcd->self.root_hub->dev); + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT); if (ret) goto dealloc_usb2_hcd; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 82391a0dbc7b..aab1c7903288 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -138,7 +138,13 @@ static int xhci_start(struct xhci_hcd *xhci) { u32 temp; int ret; + struct usb_hcd *hcd = xhci_to_hcd(xhci); + /* + * disable irq to avoid xhci_irq flooding due to unhandeled port + * change event in halt state, as soon as xhci_start clears halt bit + */ + disable_irq(hcd->irq); temp = readl(&xhci->op_regs->command); temp |= (CMD_RUN); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.", @@ -159,6 +165,8 @@ static int xhci_start(struct xhci_hcd *xhci) /* clear state flags. Including dying, halted or removing */ xhci->xhc_state = 0; + enable_irq(hcd->irq); + return ret; } diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 1950e87b4219..775690bed4c0 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -787,12 +787,6 @@ static int iowarrior_probe(struct usb_interface *interface, iface_desc = interface->cur_altsetting; dev->product_id = le16_to_cpu(udev->descriptor.idProduct); - if (iface_desc->desc.bNumEndpoints < 1) { - dev_err(&interface->dev, "Invalid number of endpoints\n"); - retval = -EINVAL; - goto error; - } - /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -803,6 +797,21 @@ static int iowarrior_probe(struct usb_interface *interface, /* this one will match for the IOWarrior56 only */ dev->int_out_endpoint = endpoint; } + + if (!dev->int_in_endpoint) { + dev_err(&interface->dev, "no interrupt-in endpoint found\n"); + retval = -ENODEV; + goto error; + } + + if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) { + if (!dev->int_out_endpoint) { + dev_err(&interface->dev, "no interrupt-out endpoint found\n"); + retval = -ENODEV; + goto error; + } + } + /* we have to check the report_size often, so remember it in the endianness suitable for our machine */ dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index b03d3b867fca..9a9c82a4d35d 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -458,15 +458,11 @@ static int da8xx_musb_exit(struct musb *musb) } static const struct musb_platform_ops da8xx_ops = { - .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP, + .quirks = MUSB_INDEXED_EP, .init = da8xx_musb_init, .exit = da8xx_musb_exit, .fifo_mode = 2, -#ifdef CONFIG_USB_TI_CPPI_DMA - .dma_init = cppi_dma_controller_create, - .dma_exit = cppi_dma_controller_destroy, -#endif .enable = da8xx_musb_enable, .disable = da8xx_musb_disable, diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 935bd0778bfb..c76ca5a94557 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1417,6 +1417,7 @@ static void dr_swap(struct usbpd *pd) } pd_phy_update_roles(pd->current_dr, pd->current_pr); + dual_role_instance_changed(pd->dual_role); } @@ -2656,11 +2657,17 @@ static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role, static int usbpd_dr_prop_writeable(struct dual_role_phy_instance *dual_role, enum dual_role_property prop) { + struct usbpd *pd = dual_role_get_drvdata(dual_role); + switch (prop) { case DUAL_ROLE_PROP_MODE: + return 1; case DUAL_ROLE_PROP_DR: case DUAL_ROLE_PROP_PR: - return 1; + if (pd) + return pd->current_state == PE_SNK_READY || + pd->current_state == PE_SRC_READY; + break; default: break; } diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 64916f5566b5..aa11cf2f7417 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,10 +27,10 @@ #include <linux/clk/msm-clk.h> #include <linux/reset.h> -enum core_ldo_levels { - CORE_LEVEL_NONE = 0, - CORE_LEVEL_MIN, - CORE_LEVEL_MAX, +enum ldo_levels { + VOLTAGE_LEVEL_NONE = 0, + VOLTAGE_LEVEL_MIN, + VOLTAGE_LEVEL_MAX, }; #define INIT_MAX_TIME_USEC 1000 @@ -40,6 +40,8 @@ enum core_ldo_levels { #define USB_SSPHY_1P2_VOL_MAX 1200000 /* uV */ #define USB_SSPHY_HPM_LOAD 23000 /* uA */ +#define USB_SSPHY_LOAD_DEFAULT -1 + /* USB3PHY_PCIE_USB3_PCS_PCS_STATUS bit */ #define PHYSTATUS BIT(6) @@ -83,6 +85,9 @@ struct msm_ssphy_qmp { int vdd_levels[3]; /* none, low, high */ struct regulator *core_ldo; int core_voltage_levels[3]; + struct regulator *fpc_redrive_ldo; + int redrive_voltage_levels[3]; + int redrive_load; struct clk *ref_clk_src; struct clk *ref_clk; struct clk *aux_clk; @@ -162,6 +167,33 @@ static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy, } } +static int msm_ldo_enable(struct msm_ssphy_qmp *phy, + struct regulator *ldo, int *voltage_levels, int load) +{ + int ret = 0; + + dev_dbg(phy->phy.dev, + "ldo: min_vol:%duV max_vol:%duV\n", + voltage_levels[VOLTAGE_LEVEL_MIN], + voltage_levels[VOLTAGE_LEVEL_MAX]); + + if (load > 0) { + ret = regulator_set_load(ldo, load); + if (ret < 0) + return ret; + } + + ret = regulator_set_voltage(ldo, + voltage_levels[VOLTAGE_LEVEL_MIN], + voltage_levels[VOLTAGE_LEVEL_MAX]); + if (ret) + return ret; + + ret = regulator_enable(ldo); + + return ret; +} + static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on) { int min, rc = 0; @@ -181,74 +213,65 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on) if (!on) goto disable_regulators; - rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min], - phy->vdd_levels[2]); - if (rc) { - dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n"); - return rc; - } - - dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n", - phy->vdd_levels[min], phy->vdd_levels[2]); + if (phy->fpc_redrive_ldo) { + rc = msm_ldo_enable(phy, phy->fpc_redrive_ldo, + phy->redrive_voltage_levels, + phy->redrive_load); + if (rc < 0) { + dev_err(phy->phy.dev, + "enable phy->fpc_redrive_ldo failed\n"); + return rc; + } - rc = regulator_enable(phy->vdd); - if (rc) { - dev_err(phy->phy.dev, - "regulator_enable(phy->vdd) failed, ret=%d", - rc); - goto unconfig_vdd; + dev_dbg(phy->phy.dev, + "fpc redrive ldo: min_vol:%duV max_vol:%duV\n", + phy->redrive_voltage_levels[VOLTAGE_LEVEL_MIN], + phy->redrive_voltage_levels[VOLTAGE_LEVEL_MAX]); } - rc = regulator_set_load(phy->core_ldo, USB_SSPHY_HPM_LOAD); + rc = msm_ldo_enable(phy, phy->vdd, phy->vdd_levels, + USB_SSPHY_LOAD_DEFAULT); if (rc < 0) { - dev_err(phy->phy.dev, "Unable to set HPM of core_ldo\n"); - goto disable_vdd; + dev_err(phy->phy.dev, "enable phy->vdd failed\n"); + goto disable_fpc_redrive; } - rc = regulator_set_voltage(phy->core_ldo, - phy->core_voltage_levels[CORE_LEVEL_MIN], - phy->core_voltage_levels[CORE_LEVEL_MAX]); - if (rc) { - dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n"); - goto put_core_ldo_lpm; - } + dev_dbg(phy->phy.dev, + "vdd ldo: min_vol:%duV max_vol:%duV\n", + phy->vdd_levels[VOLTAGE_LEVEL_MIN], + phy->vdd_levels[VOLTAGE_LEVEL_MAX]); - rc = regulator_enable(phy->core_ldo); - if (rc) { - dev_err(phy->phy.dev, "Unable to enable core_ldo\n"); - goto unset_core_ldo; + rc = msm_ldo_enable(phy, phy->core_ldo, phy->core_voltage_levels, + USB_SSPHY_HPM_LOAD); + if (rc < 0) { + dev_err(phy->phy.dev, "enable phy->core_ldo failed\n"); + goto disable_vdd; } + dev_dbg(phy->phy.dev, + "core ldo: min_vol:%duV max_vol:%duV\n", + phy->core_voltage_levels[VOLTAGE_LEVEL_MIN], + phy->core_voltage_levels[VOLTAGE_LEVEL_MAX]); + return 0; disable_regulators: rc = regulator_disable(phy->core_ldo); if (rc) - dev_err(phy->phy.dev, "Unable to disable core_ldo\n"); - -unset_core_ldo: - rc = regulator_set_voltage(phy->core_ldo, - phy->core_voltage_levels[CORE_LEVEL_NONE], - phy->core_voltage_levels[CORE_LEVEL_MAX]); - if (rc) - dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n"); - -put_core_ldo_lpm: - rc = regulator_set_load(phy->core_ldo, 0); - if (rc < 0) - dev_err(phy->phy.dev, "Unable to set LPM of core_ldo\n"); + dev_err(phy->phy.dev, "disable phy->core_ldo failed\n"); disable_vdd: rc = regulator_disable(phy->vdd); if (rc) - dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d", - rc); + dev_err(phy->phy.dev, "disable phy->vdd failed\n"); -unconfig_vdd: - rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min], - phy->vdd_levels[2]); - if (rc) - dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n"); +disable_fpc_redrive: + if (phy->fpc_redrive_ldo) { + rc = regulator_disable(phy->fpc_redrive_ldo); + if (rc) + dev_err(phy->phy.dev, + "disable phy->fpc_redrive_ldo failed\n"); + } return rc < 0 ? rc : 0; } @@ -307,10 +330,6 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) phy->clk_enabled = true; } - /* select usb3 phy mode */ - if (phy->tcsr_usb3_dp_phymode) - writel_relaxed(0x0, phy->tcsr_usb3_dp_phymode); - writel_relaxed(0x01, phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); @@ -386,6 +405,10 @@ static int msm_ssphy_qmp_reset(struct usb_phy *uphy) goto deassert_phy_phy_reset; } + /* select usb3 phy mode */ + if (phy->tcsr_usb3_dp_phymode) + writel_relaxed(0x0, phy->tcsr_usb3_dp_phymode); + /* Deassert USB3 PHY CSR reset */ ret = reset_control_deassert(phy->phy_reset); if (ret) { @@ -683,9 +706,9 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) } /* Set default core voltage values */ - phy->core_voltage_levels[CORE_LEVEL_NONE] = 0; - phy->core_voltage_levels[CORE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN; - phy->core_voltage_levels[CORE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX; + phy->core_voltage_levels[VOLTAGE_LEVEL_NONE] = 0; + phy->core_voltage_levels[VOLTAGE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN; + phy->core_voltage_levels[VOLTAGE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX; if (of_get_property(dev->of_node, "qcom,core-voltage-level", &len) && len == sizeof(phy->core_voltage_levels)) { @@ -729,6 +752,39 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) goto err; } + phy->fpc_redrive_ldo = devm_regulator_get_optional(dev, "fpc-redrive"); + if (IS_ERR(phy->fpc_redrive_ldo)) { + phy->fpc_redrive_ldo = NULL; + dev_dbg(dev, "no FPC re-drive ldo regulator\n"); + } else { + if (of_get_property(dev->of_node, + "qcom,redrive-voltage-level", &len) && + len == sizeof(phy->redrive_voltage_levels)) { + ret = of_property_read_u32_array(dev->of_node, + "qcom,redrive-voltage-level", + (u32 *) phy->redrive_voltage_levels, + len / sizeof(u32)); + if (ret) { + dev_err(dev, + "err qcom,redrive-voltage-level\n"); + goto err; + } + } else { + ret = -EINVAL; + dev_err(dev, "err inputs for redrive-voltage-level\n"); + goto err; + } + + ret = of_property_read_u32(dev->of_node, "qcom,redrive-load", + &phy->redrive_load); + if (ret) { + dev_err(&pdev->dev, "unable to read redrive load\n"); + goto err; + } + + dev_dbg(dev, "Get FPC re-drive ldo regulator\n"); + } + phy->ref_clk_src = devm_clk_get(dev, "ref_clk_src"); if (IS_ERR(phy->ref_clk_src)) phy->ref_clk_src = NULL; diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 1532cde8a437..7812052dc700 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -99,10 +99,17 @@ static int ark3116_read_reg(struct usb_serial *serial, usb_rcvctrlpipe(serial->dev, 0), 0xfe, 0xc0, 0, reg, buf, 1, ARK_TIMEOUT); - if (result < 0) + if (result < 1) { + dev_err(&serial->interface->dev, + "failed to read register %u: %d\n", + reg, result); + if (result >= 0) + result = -EIO; + return result; - else - return buf[0]; + } + + return buf[0]; } static inline int calc_divisor(int bps) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index fe7452f0f38a..33cec50978b8 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -171,6 +171,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */ + { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */ + { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */ { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 3df7b7ec178e..e0b1fe2f60e1 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1483,16 +1483,20 @@ static int digi_read_oob_callback(struct urb *urb) struct usb_serial *serial = port->serial; struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); + unsigned char *buf = urb->transfer_buffer; int opcode, line, status, val; int i; unsigned int rts; + if (urb->actual_length < 4) + return -1; + /* handle each oob command */ - for (i = 0; i < urb->actual_length - 3;) { - opcode = ((unsigned char *)urb->transfer_buffer)[i++]; - line = ((unsigned char *)urb->transfer_buffer)[i++]; - status = ((unsigned char *)urb->transfer_buffer)[i++]; - val = ((unsigned char *)urb->transfer_buffer)[i++]; + for (i = 0; i < urb->actual_length - 3; i += 4) { + opcode = buf[i]; + line = buf[i + 1]; + status = buf[i + 2]; + val = buf[i + 3]; dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", opcode, line, status, val); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d3d6ec455151..19a98116c2ab 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1807,8 +1807,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) mutex_init(&priv->cfg_lock); - priv->flags = ASYNC_LOW_LATENCY; - if (quirk && quirk->port_probe) quirk->port_probe(priv); @@ -2072,6 +2070,20 @@ static int ftdi_process_packet(struct usb_serial_port *port, priv->prev_status = status; } + /* save if the transmitter is empty or not */ + if (packet[1] & FTDI_RS_TEMT) + priv->transmit_empty = 1; + else + priv->transmit_empty = 0; + + len -= 2; + if (!len) + return 0; /* status only */ + + /* + * Break and error status must only be processed for packets with + * data payload to avoid over-reporting. + */ flag = TTY_NORMAL; if (packet[1] & FTDI_RS_ERR_MASK) { /* Break takes precedence over parity, which takes precedence @@ -2094,15 +2106,6 @@ static int ftdi_process_packet(struct usb_serial_port *port, } } - /* save if the transmitter is empty or not */ - if (packet[1] & FTDI_RS_TEMT) - priv->transmit_empty = 1; - else - priv->transmit_empty = 0; - - len -= 2; - if (!len) - return 0; /* status only */ port->icount.rx += len; ch = packet + 2; @@ -2433,8 +2436,12 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) { + + /* NOTE: We allow short responses and handle that below. */ + if (ret < 1) { dev_err(&port->dev, "failed to get modem status: %d\n", ret); + if (ret >= 0) + ret = -EIO; ret = usb_translate_errors(ret); goto out; } diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c02808a30436..f1a8fdcd8674 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1674,6 +1674,12 @@ static void edge_interrupt_callback(struct urb *urb) function = TIUMP_GET_FUNC_FROM_CODE(data[0]); dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__, port_number, function, data[1]); + + if (port_number >= edge_serial->serial->num_ports) { + dev_err(dev, "bad port number %d\n", port_number); + goto exit; + } + port = edge_serial->serial->port[port_number]; edge_port = usb_get_serial_port_data(port); if (!edge_port) { @@ -1755,7 +1761,7 @@ static void edge_bulk_in_callback(struct urb *urb) port_number = edge_port->port->port_number; - if (edge_port->lsr_event) { + if (urb->actual_length > 0 && edge_port->lsr_event) { edge_port->lsr_event = 0; dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n", __func__, port_number, edge_port->lsr_mask, *data); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 97ea52b5cfd4..d17685cc00c9 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1024,6 +1024,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) * (can't set it up in mos7840_startup as the structures * * were not set up at that time.) */ if (port0->open_ports == 1) { + /* FIXME: Buffer never NULL, so URB is not submitted. */ if (serial->port[0]->interrupt_in_buffer == NULL) { /* set up interrupt urb */ usb_fill_int_urb(serial->port[0]->interrupt_in_urb, @@ -2119,7 +2120,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) static int mos7840_attach(struct usb_serial *serial) { if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) { + serial->num_bulk_out < serial->num_ports || + serial->num_interrupt_in < 1) { dev_err(&serial->interface->dev, "missing endpoints\n"); return -ENODEV; } diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index a180b17d2432..76564b3bebb9 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -142,12 +142,6 @@ static int omninet_port_remove(struct usb_serial_port *port) static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport; - - wport = serial->port[1]; - tty_port_tty_set(&wport->port, tty); - return usb_serial_generic_open(tty, port); } diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 4b7bfb394a32..64bf258e7e00 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -142,7 +142,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(port->serial->dev, port->read_urb->pipe); res = usb_serial_generic_open(tty, port); - if (!res) + if (res) return res; /* Request CTS line state, sometimes during opening the current diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index b2dff0f14743..236ea43f7815 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -205,6 +205,11 @@ static void safe_process_read_urb(struct urb *urb) if (!safe) goto out; + if (length < 2) { + dev_err(&port->dev, "malformed packet\n"); + return; + } + fcs = fcs_compute10(data, length, CRC10_INITFCS); if (fcs) { dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 475e6c31b266..ddfd787c461c 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -232,11 +232,17 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status) ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_UART_STATUS, GET_UART_STATUS_TYPE, 0, GET_UART_STATUS_MSR, buf, 1, 100); - if (ret < 0) + if (ret < 1) { dev_err(&port->dev, "failed to get modem status: %d\n", ret); + if (ret >= 0) + ret = -EIO; + goto out; + } dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf); *status = *buf; + ret = 0; +out: kfree(buf); return ret; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 101aa508b8f0..67adc46d1e39 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1013,9 +1013,10 @@ static int dp_get_cable_status(struct platform_device *pdev, u32 vote) return hpd; } -static bool mdss_dp_is_dvi_mode(struct mdss_dp_drv_pdata *dp) +static bool mdss_dp_sink_audio_supp(struct mdss_dp_drv_pdata *dp) { - return hdmi_edid_is_dvi_mode(dp->panel_data.panel_info.edid_data); + return hdmi_edid_is_audio_supported( + dp->panel_data.panel_info.edid_data); } static int dp_audio_info_setup(struct platform_device *pdev, @@ -1706,14 +1707,17 @@ static int mdss_dp_send_audio_notification( goto end; } - if (!mdss_dp_is_dvi_mode(dp) || dp->audio_test_req) { + if (mdss_dp_sink_audio_supp(dp) || dp->audio_test_req) { dp->audio_test_req = false; + pr_debug("sending audio notification\n"); flags |= MSM_EXT_DISP_HPD_AUDIO; if (dp->ext_audio_data.intf_ops.hpd) ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, dp->ext_audio_data.type, val, flags); + } else { + pr_debug("sink does not support audio\n"); } end: diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index b1944a9a6323..17722eac3006 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1463,15 +1463,6 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) if (mipi->init_delay) usleep_range(mipi->init_delay, mipi->init_delay); - if (mipi->force_clk_lane_hs) { - u32 tmp; - - tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac); - tmp |= (1<<28); - MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp); - wmb(); - } - if (pdata->panel_info.type == MIPI_CMD_PANEL) mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle, MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 66c0cb029720..2a76466abf3e 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -699,6 +699,8 @@ void mdss_dsi_dsc_config(struct mdss_dsi_ctrl_pdata *ctrl, struct dsc_desc *dsc); void mdss_dsi_dfps_config_8996(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_set_burst_mode(struct mdss_dsi_ctrl_pdata *ctrl); +void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, + u32 bits, int set); void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off, u32 mask, u32 val); int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl); diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 982e7a02ffa3..9f4b7eb52492 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -602,7 +602,7 @@ error: return rc; } -static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, +void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 bits, int set) { u32 data; @@ -613,6 +613,7 @@ static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, else data &= ~bits; MIPI_OUTP(ctrl->ctrl_base + 0x0ac, data); + wmb(); /* make sure write happens */ } diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index bf66c0cd430c..fe79b6fd52b4 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1275,6 +1275,7 @@ static int mdss_fb_probe(struct platform_device *pdev) mfd->fb_imgType = MDP_RGBA_8888; mfd->calib_mode_bl = 0; mfd->unset_bl_level = U32_MAX; + mfd->bl_extn_level = -1; mfd->pdev = pdev; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 6bf8e581326d..502bc1570609 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -137,6 +137,7 @@ struct hdmi_edid_ctrl { u16 video_latency; u32 present_3d; u32 page_id; + bool basic_audio_supp; u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE]; int adb_size; u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE]; @@ -1289,6 +1290,14 @@ static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, return; } + /* Check if sink supports basic audio */ + if (in_buf[3] & BIT(6)) + edid_ctrl->basic_audio_supp = true; + else + edid_ctrl->basic_audio_supp = false; + pr_debug("%s: basic audio supported: %s\n", __func__, + edid_ctrl->basic_audio_supp ? "true" : "false"); + vsd = hdmi_edid_find_hfvsdb(in_buf); if (vsd) { @@ -2627,6 +2636,17 @@ void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz) edid_ctrl->init_data.max_pclk_khz = max_pclk_khz; } +bool hdmi_edid_is_audio_supported(void *input) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + /* + * return true if basic audio is supported or if an audio + * data block was successfully parsed. + */ + return (edid_ctrl->basic_audio_supp || edid_ctrl->adb_size); +} + void hdmi_edid_deinit(void *input) { struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 653276683981..557e9326a81d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -80,5 +80,6 @@ void hdmi_edid_get_hdr_data(void *edid_ctrl, void hdmi_edid_config_override(void *input, bool enable, struct hdmi_edid_override_data *data); void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz); +bool hdmi_edid_is_audio_supported(void *input); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index b09e771c4ea6..171f44815430 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -2179,6 +2179,8 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) mdss_set_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED); break; case MDSS_MDP_HW_REV_320: + mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); + mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT); case MDSS_MDP_HW_REV_330: mdata->max_target_zorder = 7; /* excluding base layer */ mdata->max_cursor_size = 512; @@ -2218,8 +2220,6 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) set_bit(MDSS_CAPS_MDP_VOTE_CLK_NOT_SUPPORTED, mdata->mdss_caps_map); mdss_mdp_init_default_prefill_factors(mdata); - mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); - mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT); mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE); mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE); mdss_set_quirk(mdata, MDSS_QUIRK_DMA_BI_DIR); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 3e6b576cfb6e..a3511a1a07ef 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -1710,12 +1710,42 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg) return 0; } +static int mdss_mdp_video_splash_handoff(struct mdss_mdp_ctl *ctl) +{ + int i, ret = 0; + u32 data, flush; + + ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN, + NULL, CTL_INTF_EVENT_FLAG_DEFAULT); + + if (ret) { + pr_err("%s:ctl%d failed to handle 'CONT_SPLASH_BEGIN' event\n" + , __func__, ctl->num); + return ret; + } + + /* clear up mixer0 and mixer1 */ + flush = 0; + for (i = 0; i < 2; i++) { + data = mdss_mdp_ctl_read(ctl, + MDSS_MDP_REG_CTL_LAYER(i)); + if (data) { + mdss_mdp_ctl_write(ctl, + MDSS_MDP_REG_CTL_LAYER(i), + MDSS_MDP_LM_BORDER_COLOR); + flush |= (0x40 << i); + } + } + mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush); + + return ret; +} + int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff) { struct mdss_panel_data *pdata; - int i, ret = 0, off; - u32 data, flush; + int ret = 0, off; struct mdss_mdp_video_ctx *ctx, *sctx = NULL; struct mdss_mdp_ctl *sctl; @@ -1749,29 +1779,20 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, } if (!handoff) { - ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN, - NULL, CTL_INTF_EVENT_FLAG_DEFAULT); - if (ret) { - pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n" - , __func__); - return ret; - } + ret = mdss_mdp_video_splash_handoff(ctl); - /* clear up mixer0 and mixer1 */ - flush = 0; - for (i = 0; i < 2; i++) { - data = mdss_mdp_ctl_read(ctl, - MDSS_MDP_REG_CTL_LAYER(i)); - if (data) { - mdss_mdp_ctl_write(ctl, - MDSS_MDP_REG_CTL_LAYER(i), - MDSS_MDP_LM_BORDER_COLOR); - flush |= (0x40 << i); - } - } - mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush); + if (!ret && sctl) + ret = mdss_mdp_video_splash_handoff(sctl); + + if (ret) + return ret; mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0); + + if (sctx) + mdp_video_write(sctx, + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0); + mdss_mdp_video_timegen_flush(ctl, sctx); /* wait for 1 VSYNC for the pipe to be unstaged */ @@ -1780,6 +1801,12 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL, CTL_INTF_EVENT_FLAG_DEFAULT); + + if (!ret && sctl) + ret = mdss_mdp_ctl_intf_event(sctl, + MDSS_EVENT_CONT_SPLASH_FINISH, NULL, + CTL_INTF_EVENT_FLAG_DEFAULT); + } return ret; diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index fce667a2126d..7c6938d40e0b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -1222,6 +1222,15 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, goto end; } + /* scaling is not allowed for solid_fill layers */ + if ((pipe->flags & MDP_SOLID_FILL) && + ((pipe->src.w != pipe->dst.w) || + (pipe->src.h != pipe->dst.h))) { + pr_err("solid fill pipe:%d cannot have scaling\n", pipe->num); + ret = -EINVAL; + goto end; + } + /* * unstage the pipe if it's current z_order does not match with new * z_order because client may only call the validate. diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index 0307d570ff64..fdd1c0153ce0 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -2065,10 +2065,12 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, return ret; } + mutex_lock(&mgr->lock); perf = mdss_rotator_find_session(private, config.session_id); if (!perf) { pr_err("No session with id=%u could be found\n", config.session_id); + mutex_unlock(&mgr->lock); return -EINVAL; } @@ -2091,6 +2093,7 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, config.output.format); done: ATRACE_END(__func__); + mutex_unlock(&mgr->lock); return ret; } diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 0e0d2621496e..03e78733d168 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -1863,8 +1863,10 @@ static int mdss_dsi_ulps_config_default(struct mdss_dsi_ctrl_pdata *ctrl, * to be in stop state. */ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 16); + wmb(); /* ensure lanes are put to stop state */ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, 0x0); + wmb(); /* ensure lanes are in proper state */ lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8); } @@ -2272,6 +2274,8 @@ int mdss_dsi_pre_clkoff_cb(void *priv, pdata = &ctrl->panel_data; if ((clk & MDSS_DSI_LINK_CLK) && (new_state == MDSS_DSI_CLK_OFF)) { + if (pdata->panel_info.mipi.force_clk_lane_hs) + mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 0); /* * If ULPS feature is enabled, enter ULPS first. * However, when blanking the panel, we should enter ULPS @@ -2387,6 +2391,8 @@ int mdss_dsi_post_clkon_cb(void *priv, goto error; } } + if (pdata->panel_info.mipi.force_clk_lane_hs) + mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 1); } error: return rc; diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index 049a884a756f..59d74d1b47a8 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -153,6 +153,9 @@ struct ds_device */ u16 spu_bit; + u8 st_buf[ST_SIZE]; + u8 byte_buf; + struct w1_bus_master master; }; @@ -174,7 +177,6 @@ struct ds_status u8 data_in_buffer_status; u8 reserved1; u8 reserved2; - }; static struct usb_device_id ds_id_table [] = { @@ -244,28 +246,6 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index) return err; } -static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, - unsigned char *buf, int size) -{ - int count, err; - - memset(st, 0, sizeof(*st)); - - count = 0; - err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev, - dev->ep[EP_STATUS]), buf, size, &count, 1000); - if (err < 0) { - pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n", - dev->ep[EP_STATUS], err); - return err; - } - - if (count >= sizeof(*st)) - memcpy(st, buf, sizeof(*st)); - - return count; -} - static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off) { pr_info("%45s: %8x\n", str, buf[off]); @@ -324,6 +304,35 @@ static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count) } } +static int ds_recv_status(struct ds_device *dev, struct ds_status *st, + bool dump) +{ + int count, err; + + if (st) + memset(st, 0, sizeof(*st)); + + count = 0; + err = usb_interrupt_msg(dev->udev, + usb_rcvintpipe(dev->udev, + dev->ep[EP_STATUS]), + dev->st_buf, sizeof(dev->st_buf), + &count, 1000); + if (err < 0) { + pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n", + dev->ep[EP_STATUS], err); + return err; + } + + if (dump) + ds_dump_status(dev, dev->st_buf, count); + + if (st && count >= sizeof(*st)) + memcpy(st, dev->st_buf, sizeof(*st)); + + return count; +} + static void ds_reset_device(struct ds_device *dev) { ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0); @@ -344,7 +353,6 @@ static void ds_reset_device(struct ds_device *dev) static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) { int count, err; - struct ds_status st; /* Careful on size. If size is less than what is available in * the input buffer, the device fails the bulk transfer and @@ -359,14 +367,9 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), buf, size, &count, 1000); if (err < 0) { - u8 buf[ST_SIZE]; - int count; - pr_info("Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]); usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN])); - - count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf)); - ds_dump_status(dev, buf, count); + ds_recv_status(dev, NULL, true); return err; } @@ -404,7 +407,6 @@ int ds_stop_pulse(struct ds_device *dev, int limit) { struct ds_status st; int count = 0, err = 0; - u8 buf[ST_SIZE]; do { err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0); @@ -413,7 +415,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit) err = ds_send_control(dev, CTL_RESUME_EXE, 0); if (err) break; - err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf)); + err = ds_recv_status(dev, &st, false); if (err) break; @@ -456,18 +458,17 @@ int ds_detect(struct ds_device *dev, struct ds_status *st) static int ds_wait_status(struct ds_device *dev, struct ds_status *st) { - u8 buf[ST_SIZE]; int err, count = 0; do { st->status = 0; - err = ds_recv_status_nodump(dev, st, buf, sizeof(buf)); + err = ds_recv_status(dev, st, false); #if 0 if (err >= 0) { int i; printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err); for (i=0; i<err; ++i) - printk("%02x ", buf[i]); + printk("%02x ", dev->st_buf[i]); printk("\n"); } #endif @@ -485,7 +486,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st) * can do something with it). */ if (err > 16 || count >= 100 || err < 0) - ds_dump_status(dev, buf, err); + ds_dump_status(dev, dev->st_buf, err); /* Extended data isn't an error. Well, a short is, but the dump * would have already told the user that and we can't do anything @@ -608,7 +609,6 @@ static int ds_write_byte(struct ds_device *dev, u8 byte) { int err; struct ds_status st; - u8 rbyte; err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte); if (err) @@ -621,11 +621,11 @@ static int ds_write_byte(struct ds_device *dev, u8 byte) if (err) return err; - err = ds_recv_data(dev, &rbyte, sizeof(rbyte)); + err = ds_recv_data(dev, &dev->byte_buf, 1); if (err < 0) return err; - return !(byte == rbyte); + return !(byte == dev->byte_buf); } static int ds_read_byte(struct ds_device *dev, u8 *byte) @@ -712,7 +712,6 @@ static void ds9490r_search(void *data, struct w1_master *master, int err; u16 value, index; struct ds_status st; - u8 st_buf[ST_SIZE]; int search_limit; int found = 0; int i; @@ -724,7 +723,12 @@ static void ds9490r_search(void *data, struct w1_master *master, /* FIFO 128 bytes, bulk packet size 64, read a multiple of the * packet size. */ - u64 buf[2*64/8]; + const size_t bufsize = 2 * 64; + u64 *buf; + + buf = kmalloc(bufsize, GFP_KERNEL); + if (!buf) + return; mutex_lock(&master->bus_mutex); @@ -745,10 +749,9 @@ static void ds9490r_search(void *data, struct w1_master *master, do { schedule_timeout(jtime); - if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) < - sizeof(st)) { + err = ds_recv_status(dev, &st, false); + if (err < 0 || err < sizeof(st)) break; - } if (st.data_in_buffer_status) { /* Bulk in can receive partial ids, but when it does @@ -758,7 +761,7 @@ static void ds9490r_search(void *data, struct w1_master *master, * bulk without first checking if status says there * is data to read. */ - err = ds_recv_data(dev, (u8 *)buf, sizeof(buf)); + err = ds_recv_data(dev, (u8 *)buf, bufsize); if (err < 0) break; for (i = 0; i < err/8; ++i) { @@ -794,9 +797,14 @@ static void ds9490r_search(void *data, struct w1_master *master, } search_out: mutex_unlock(&master->bus_mutex); + kfree(buf); } #if 0 +/* + * FIXME: if this disabled code is ever used in the future all ds_send_data() + * calls must be changed to use a DMAable buffer. + */ static int ds_match_access(struct ds_device *dev, u64 init) { int err; @@ -845,13 +853,12 @@ static int ds_set_path(struct ds_device *dev, u64 init) static u8 ds9490r_touch_bit(void *data, u8 bit) { - u8 ret; struct ds_device *dev = data; - if (ds_touch_bit(dev, bit, &ret)) + if (ds_touch_bit(dev, bit, &dev->byte_buf)) return 0; - return ret; + return dev->byte_buf; } #if 0 @@ -866,13 +873,12 @@ static u8 ds9490r_read_bit(void *data) { struct ds_device *dev = data; int err; - u8 bit = 0; - err = ds_touch_bit(dev, 1, &bit); + err = ds_touch_bit(dev, 1, &dev->byte_buf); if (err) return 0; - return bit & 1; + return dev->byte_buf & 1; } #endif @@ -887,32 +893,52 @@ static u8 ds9490r_read_byte(void *data) { struct ds_device *dev = data; int err; - u8 byte = 0; - err = ds_read_byte(dev, &byte); + err = ds_read_byte(dev, &dev->byte_buf); if (err) return 0; - return byte; + return dev->byte_buf; } static void ds9490r_write_block(void *data, const u8 *buf, int len) { struct ds_device *dev = data; + u8 *tbuf; + + if (len <= 0) + return; + + tbuf = kmalloc(len, GFP_KERNEL); + if (!tbuf) + return; - ds_write_block(dev, (u8 *)buf, len); + memcpy(tbuf, buf, len); + ds_write_block(dev, tbuf, len); + + kfree(tbuf); } static u8 ds9490r_read_block(void *data, u8 *buf, int len) { struct ds_device *dev = data; int err; + u8 *tbuf; - err = ds_read_block(dev, buf, len); - if (err < 0) + if (len <= 0) + return 0; + + tbuf = kmalloc(len, GFP_KERNEL); + if (!tbuf) return 0; - return len; + err = ds_read_block(dev, tbuf, len); + if (err >= 0) + memcpy(buf, tbuf, len); + + kfree(tbuf); + + return err >= 0 ? len : 0; } static u8 ds9490r_reset(void *data) diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c9a7ff67d395..39886edfa222 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -763,6 +763,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__, sl->name); w1_family_put(sl->family); + atomic_dec(&sl->master->refcnt); kfree(sl); return err; } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 239bc9cba28c..f54f77037d22 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -644,6 +644,9 @@ static void __unregister_request(struct ceph_mds_client *mdsc, { dout("__unregister_request %p tid %lld\n", req, req->r_tid); + /* Never leave an unregistered request on an unsafe list! */ + list_del_init(&req->r_unsafe_item); + if (req->r_tid == mdsc->oldest_tid) { struct rb_node *p = rb_next(&req->r_node); mdsc->oldest_tid = 0; @@ -1051,7 +1054,6 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc, while (!list_empty(&session->s_unsafe)) { req = list_first_entry(&session->s_unsafe, struct ceph_mds_request, r_unsafe_item); - list_del_init(&req->r_unsafe_item); pr_warn_ratelimited(" dropping unsafe request %llu\n", req->r_tid); __unregister_request(mdsc, req); @@ -2477,7 +2479,6 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) * useful we could do with a revised return value. */ dout("got safe reply %llu, mds%d\n", tid, mds); - list_del_init(&req->r_unsafe_item); /* last unsafe request during umount? */ if (mdsc->stopping && !__get_oldest_req(mdsc)) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9da42ace762a..8a456f9b8a44 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5362,7 +5362,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, ext4_lblk_t stop, *iterator, ex_start, ex_end; /* Let path point to the last extent */ - path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0); + path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, + EXT4_EX_NOCACHE); if (IS_ERR(path)) return PTR_ERR(path); @@ -5371,15 +5372,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, if (!extent) goto out; - stop = le32_to_cpu(extent->ee_block) + - ext4_ext_get_actual_len(extent); + stop = le32_to_cpu(extent->ee_block); /* * In case of left shift, Don't start shifting extents until we make * sure the hole is big enough to accommodate the shift. */ if (SHIFT == SHIFT_LEFT) { - path = ext4_find_extent(inode, start - 1, &path, 0); + path = ext4_find_extent(inode, start - 1, &path, + EXT4_EX_NOCACHE); if (IS_ERR(path)) return PTR_ERR(path); depth = path->p_depth; @@ -5411,9 +5412,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, else iterator = &stop; - /* Its safe to start updating extents */ - while (start < stop) { - path = ext4_find_extent(inode, *iterator, &path, 0); + /* + * Its safe to start updating extents. Start and stop are unsigned, so + * in case of right shift if extent with 0 block is reached, iterator + * becomes NULL to indicate the end of the loop. + */ + while (iterator && start <= stop) { + path = ext4_find_extent(inode, *iterator, &path, + EXT4_EX_NOCACHE); if (IS_ERR(path)) return PTR_ERR(path); depth = path->p_depth; @@ -5440,8 +5446,11 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, ext4_ext_get_actual_len(extent); } else { extent = EXT_FIRST_EXTENT(path[depth].p_hdr); - *iterator = le32_to_cpu(extent->ee_block) > 0 ? - le32_to_cpu(extent->ee_block) - 1 : 0; + if (le32_to_cpu(extent->ee_block) > 0) + *iterator = le32_to_cpu(extent->ee_block) - 1; + else + /* Beginning is reached, end of the loop */ + iterator = NULL; /* Update path extent in case we need to stop */ while (le32_to_cpu(extent->ee_block) < start) extent++; diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 66eed657701c..cb3d6f6419cd 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -933,8 +933,15 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, struct page *page) { int i_size_changed = 0; + int ret; - copied = ext4_write_inline_data_end(inode, pos, len, copied, page); + ret = ext4_write_inline_data_end(inode, pos, len, copied, page); + if (ret < 0) { + unlock_page(page); + put_page(page); + return ret; + } + copied = ret; /* * No need to use i_size_read() here, the i_size diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 55841e20ec3e..99fa2fca52b1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1167,8 +1167,11 @@ static int ext4_write_end(struct file *file, if (ext4_has_inline_data(inode)) { ret = ext4_write_inline_data_end(inode, pos, len, copied, page); - if (ret < 0) + if (ret < 0) { + unlock_page(page); + put_page(page); goto errout; + } copied = ret; } else copied = block_write_end(file, mapping, pos, @@ -1222,7 +1225,9 @@ errout: * set the buffer to be dirty, since in data=journalled mode we need * to call ext4_handle_dirty_metadata() instead. */ -static void zero_new_buffers(struct page *page, unsigned from, unsigned to) +static void ext4_journalled_zero_new_buffers(handle_t *handle, + struct page *page, + unsigned from, unsigned to) { unsigned int block_start = 0, block_end; struct buffer_head *head, *bh; @@ -1239,7 +1244,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to) size = min(to, block_end) - start; zero_user(page, start, size); - set_buffer_uptodate(bh); + write_end_fn(handle, bh); } clear_buffer_new(bh); } @@ -1268,18 +1273,25 @@ static int ext4_journalled_write_end(struct file *file, BUG_ON(!ext4_handle_valid(handle)); - if (ext4_has_inline_data(inode)) - copied = ext4_write_inline_data_end(inode, pos, len, - copied, page); - else { - if (copied < len) { - if (!PageUptodate(page)) - copied = 0; - zero_new_buffers(page, from+copied, to); + if (ext4_has_inline_data(inode)) { + ret = ext4_write_inline_data_end(inode, pos, len, + copied, page); + if (ret < 0) { + unlock_page(page); + put_page(page); + goto errout; } - + copied = ret; + } else if (unlikely(copied < len) && !PageUptodate(page)) { + copied = 0; + ext4_journalled_zero_new_buffers(handle, page, from, to); + } else { + if (unlikely(copied < len)) + ext4_journalled_zero_new_buffers(handle, page, + from + copied, to); ret = ext4_walk_page_buffers(handle, page_buffers(page), from, - to, &partial, write_end_fn); + from + copied, &partial, + write_end_fn); if (!partial) SetPageUptodate(page); } @@ -1305,6 +1317,7 @@ static int ext4_journalled_write_end(struct file *file, */ ext4_orphan_add(handle, inode); +errout: ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; @@ -3567,6 +3580,10 @@ static int ext4_block_truncate_page(handle_t *handle, unsigned blocksize; struct inode *inode = mapping->host; + /* If we are processing an encrypted inode during orphan list handling */ + if (ext4_encrypted_inode(inode) && !ext4_has_encryption_key(inode)) + return 0; + blocksize = inode->i_sb->s_blocksize; length = blocksize - (offset & (blocksize - 1)); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index be1227c196d8..c2810503eb50 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3121,6 +3121,13 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, if (ar->pright && start + size - 1 >= ar->lright) size -= start + size - ar->lright; + /* + * Trim allocation request for filesystems with artificially small + * groups. + */ + if (size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)) + size = EXT4_BLOCKS_PER_GROUP(ac->ac_sb); + end = start + size; /* check we don't cross already preallocated blocks */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b405a7b74ce0..6fe8e30eeb99 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -793,6 +793,7 @@ static void ext4_put_super(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; + int aborted = 0; int i, err; ext4_unregister_li_request(sb); @@ -802,9 +803,10 @@ static void ext4_put_super(struct super_block *sb) destroy_workqueue(sbi->rsv_conversion_wq); if (sbi->s_journal) { + aborted = is_journal_aborted(sbi->s_journal); err = jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; - if (err < 0) + if ((err < 0) && !aborted) ext4_abort(sb, "Couldn't clean up the journal"); } @@ -816,7 +818,7 @@ static void ext4_put_super(struct super_block *sb) ext4_ext_release(sb); ext4_xattr_put_super(sb); - if (!(sb->s_flags & MS_RDONLY)) { + if (!(sb->s_flags & MS_RDONLY) && !aborted) { ext4_clear_feature_journal_needs_recovery(sb); es->s_state = cpu_to_le16(sbi->s_mount_state); } @@ -3746,7 +3748,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) * root first: it may be modified in the journal! */ if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) { - if (ext4_load_journal(sb, es, journal_devnum)) + err = ext4_load_journal(sb, es, journal_devnum); + if (err) goto failed_mount3a; } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) && ext4_has_feature_journal_needs_recovery(sb)) { diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 972eab7ac071..f53826ec30f3 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -742,6 +742,10 @@ static int get_data_block_dio(struct inode *inode, sector_t iblock, static int get_data_block_bmap(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { + /* Block number less than F2FS MAX BLOCKS */ + if (unlikely(iblock >= max_file_size(0))) + return -EFBIG; + return __get_data_block(inode, iblock, bh_result, create, F2FS_GET_BLOCK_BMAP); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9db5500d63d9..3c7594b9d109 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1715,6 +1715,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) * super.c */ int f2fs_commit_super(struct f2fs_sb_info *, bool); +loff_t max_file_size(unsigned bits); int f2fs_sync_fs(struct super_block *, int); extern __printf(3, 4) void f2fs_msg(struct super_block *, const char *, const char *, ...); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 3a65e0132352..106dda1e743d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -898,7 +898,7 @@ static const struct export_operations f2fs_export_ops = { .get_parent = f2fs_get_parent, }; -static loff_t max_file_size(unsigned bits) +loff_t max_file_size(unsigned bits) { loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS); loff_t leaf_count = ADDRS_PER_BLOCK; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 509411dd3698..cf644d52c0cf 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1269,6 +1269,16 @@ out: return 0; } +static void fat_dummy_inode_init(struct inode *inode) +{ + /* Initialize this dummy inode to work as no-op. */ + MSDOS_I(inode)->mmu_private = 0; + MSDOS_I(inode)->i_start = 0; + MSDOS_I(inode)->i_logstart = 0; + MSDOS_I(inode)->i_attrs = 0; + MSDOS_I(inode)->i_pos = 0; +} + static int fat_read_root(struct inode *inode) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); @@ -1713,12 +1723,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, fat_inode = new_inode(sb); if (!fat_inode) goto out_fail; - MSDOS_I(fat_inode)->i_pos = 0; + fat_dummy_inode_init(fat_inode); sbi->fat_inode = fat_inode; fsinfo_inode = new_inode(sb); if (!fsinfo_inode) goto out_fail; + fat_dummy_inode_init(fsinfo_inode); fsinfo_inode->i_ino = MSDOS_FSINFO_INO; sbi->fsinfo_inode = fsinfo_inode; insert_inode_hash(fsinfo_inode); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 64eb2c6ee450..66b34b14cb6b 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -113,6 +113,7 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) iput(req->misc.release.inode); fuse_put_request(ff->fc, req); } else if (sync) { + __set_bit(FR_FORCE, &req->flags); __clear_bit(FR_BACKGROUND, &req->flags); fuse_request_send(ff->fc, req); iput(req->misc.release.inode); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 32e74710b1aa..9cd8c92b953d 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -651,9 +651,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, struct kmem_cache *cachep; int ret, tries = 0; + rcu_read_lock(); gl = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms); if (gl && !lockref_get_not_dead(&gl->gl_lockref)) gl = NULL; + rcu_read_unlock(); *glp = gl; if (gl) @@ -721,15 +723,18 @@ again: if (ret == -EEXIST) { ret = 0; + rcu_read_lock(); tmp = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms); if (tmp == NULL || !lockref_get_not_dead(&tmp->gl_lockref)) { if (++tries < 100) { + rcu_read_unlock(); cond_resched(); goto again; } tmp = NULL; ret = -ENOMEM; } + rcu_read_unlock(); } else { WARN_ON_ONCE(ret); } diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index fa1b8e0dcacf..a2e724053919 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1876,7 +1876,9 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh) __blist_del_buffer(list, jh); jh->b_jlist = BJ_None; - if (test_clear_buffer_jbddirty(bh)) + if (transaction && is_journal_aborted(transaction->t_journal)) + clear_buffer_jbddirty(bh); + else if (test_clear_buffer_jbddirty(bh)) mark_buffer_dirty(bh); /* Expose it to the VM */ } diff --git a/fs/mount.h b/fs/mount.h index 14db05d424f7..3dc7dea5a357 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -86,7 +86,6 @@ static inline int is_mounted(struct vfsmount *mnt) } extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *); -extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *); extern int __legitimize_mnt(struct vfsmount *, unsigned); extern bool legitimize_mnt(struct vfsmount *, unsigned); diff --git a/fs/namespace.c b/fs/namespace.c index 4aad64ad9ad0..c1477882a853 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -639,28 +639,6 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) } /* - * find the last mount at @dentry on vfsmount @mnt. - * mount_lock must be held. - */ -struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) -{ - struct mount *p, *res = NULL; - p = __lookup_mnt(mnt, dentry); - if (!p) - goto out; - if (!(p->mnt.mnt_flags & MNT_UMOUNT)) - res = p; - hlist_for_each_entry_continue(p, mnt_hash) { - if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) - break; - if (!(p->mnt.mnt_flags & MNT_UMOUNT)) - res = p; - } -out: - return res; -} - -/* * lookup_mnt - Return the first child mount mounted at path * * "First" means first mounted chronologically. If you create the @@ -880,6 +858,13 @@ void mnt_set_mountpoint(struct mount *mnt, hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list); } +static void __attach_mnt(struct mount *mnt, struct mount *parent) +{ + hlist_add_head_rcu(&mnt->mnt_hash, + m_hash(&parent->mnt, mnt->mnt_mountpoint)); + list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); +} + /* * vfsmount lock must be held for write */ @@ -888,28 +873,45 @@ static void attach_mnt(struct mount *mnt, struct mountpoint *mp) { mnt_set_mountpoint(parent, mp, mnt); - hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry)); - list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); + __attach_mnt(mnt, parent); } -static void attach_shadowed(struct mount *mnt, - struct mount *parent, - struct mount *shadows) +void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct mount *mnt) { - if (shadows) { - hlist_add_behind_rcu(&mnt->mnt_hash, &shadows->mnt_hash); - list_add(&mnt->mnt_child, &shadows->mnt_child); - } else { - hlist_add_head_rcu(&mnt->mnt_hash, - m_hash(&parent->mnt, mnt->mnt_mountpoint)); - list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); - } + struct mountpoint *old_mp = mnt->mnt_mp; + struct dentry *old_mountpoint = mnt->mnt_mountpoint; + struct mount *old_parent = mnt->mnt_parent; + + list_del_init(&mnt->mnt_child); + hlist_del_init(&mnt->mnt_mp_list); + hlist_del_init_rcu(&mnt->mnt_hash); + + attach_mnt(mnt, parent, mp); + + put_mountpoint(old_mp); + + /* + * Safely avoid even the suggestion this code might sleep or + * lock the mount hash by taking advantage of the knowledge that + * mnt_change_mountpoint will not release the final reference + * to a mountpoint. + * + * During mounting, the mount passed in as the parent mount will + * continue to use the old mountpoint and during unmounting, the + * old mountpoint will continue to exist until namespace_unlock, + * which happens well after mnt_change_mountpoint. + */ + spin_lock(&old_mountpoint->d_lock); + old_mountpoint->d_lockref.count--; + spin_unlock(&old_mountpoint->d_lock); + + mnt_add_count(old_parent, -1); } /* * vfsmount lock must be held for write */ -static void commit_tree(struct mount *mnt, struct mount *shadows) +static void commit_tree(struct mount *mnt) { struct mount *parent = mnt->mnt_parent; struct mount *m; @@ -924,7 +926,7 @@ static void commit_tree(struct mount *mnt, struct mount *shadows) list_splice(&head, n->list.prev); - attach_shadowed(mnt, parent, shadows); + __attach_mnt(mnt, parent); touch_mnt_namespace(n); } @@ -1738,7 +1740,6 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, continue; for (s = r; s; s = next_mnt(s, r)) { - struct mount *t = NULL; if (!(flag & CL_COPY_UNBINDABLE) && IS_MNT_UNBINDABLE(s)) { s = skip_mnt_tree(s); @@ -1760,14 +1761,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, goto out; lock_mount_hash(); list_add_tail(&q->mnt_list, &res->mnt_list); - mnt_set_mountpoint(parent, p->mnt_mp, q); - if (!list_empty(&parent->mnt_mounts)) { - t = list_last_entry(&parent->mnt_mounts, - struct mount, mnt_child); - if (t->mnt_mp != p->mnt_mp) - t = NULL; - } - attach_shadowed(q, parent, t); + attach_mnt(q, parent, p->mnt_mp); unlock_mount_hash(); } } @@ -1945,10 +1939,18 @@ static int attach_recursive_mnt(struct mount *source_mnt, struct path *parent_path) { HLIST_HEAD(tree_list); + struct mountpoint *smp; struct mount *child, *p; struct hlist_node *n; int err; + /* Preallocate a mountpoint in case the new mounts need + * to be tucked under other mounts. + */ + smp = get_mountpoint(source_mnt->mnt.mnt_root); + if (IS_ERR(smp)) + return PTR_ERR(smp); + if (IS_MNT_SHARED(dest_mnt)) { err = invent_group_ids(source_mnt, true); if (err) @@ -1968,16 +1970,19 @@ static int attach_recursive_mnt(struct mount *source_mnt, touch_mnt_namespace(source_mnt->mnt_ns); } else { mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); - commit_tree(source_mnt, NULL); + commit_tree(source_mnt); } hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) { struct mount *q; hlist_del_init(&child->mnt_hash); - q = __lookup_mnt_last(&child->mnt_parent->mnt, - child->mnt_mountpoint); - commit_tree(child, q); + q = __lookup_mnt(&child->mnt_parent->mnt, + child->mnt_mountpoint); + if (q) + mnt_change_mountpoint(child, smp, q); + commit_tree(child); } + put_mountpoint(smp); unlock_mount_hash(); return 0; @@ -1990,6 +1995,10 @@ static int attach_recursive_mnt(struct mount *source_mnt, unlock_mount_hash(); cleanup_group_ids(source_mnt, NULL); out: + read_seqlock_excl(&mount_lock); + put_mountpoint(smp); + read_sequnlock_excl(&mount_lock); + return err; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9a524e763c3e..4e3679b25b9b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2452,6 +2452,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, ret = PTR_ERR(state); if (IS_ERR(state)) goto out; + ctx->state = state; if (server->caps & NFS_CAP_POSIX_LOCK) set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); @@ -2474,7 +2475,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, if (ret != 0) goto out; - ctx->state = state; if (d_inode(dentry) == state->inode) { nfs_inode_attach_open_context(ctx); if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) @@ -4711,7 +4711,7 @@ out: */ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) { - struct page *pages[NFS4ACL_MAXPAGES] = {NULL, }; + struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, }; struct nfs_getaclargs args = { .fh = NFS_FH(inode), .acl_pages = pages, @@ -4725,13 +4725,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu .rpc_argp = &args, .rpc_resp = &res, }; - unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE); + unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1; int ret = -ENOMEM, i; - /* As long as we're doing a round trip to the server anyway, - * let's be prepared for a page of acl data. */ - if (npages == 0) - npages = 1; if (npages > ARRAY_SIZE(pages)) return -ERANGE; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4e4441216804..1cb50bb898b0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2487,7 +2487,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, encode_compound_hdr(xdr, req, &hdr); encode_sequence(xdr, &args->seq_args, &hdr); encode_putfh(xdr, args->fh, &hdr); - replen = hdr.replen + op_decode_hdr_maxsz + 1; + replen = hdr.replen + op_decode_hdr_maxsz; encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr); xdr_inline_pages(&req->rq_rcv_buf, replen << 2, diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 994d66fbb446..91e0c5429b4d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -369,7 +369,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, __be32 err; int host_err; bool get_write_count; - int size_change = 0; + bool size_change = (iap->ia_valid & ATTR_SIZE); if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; @@ -382,11 +382,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err) - goto out; + return err; if (get_write_count) { host_err = fh_want_write(fhp); if (host_err) - return nfserrno(host_err); + goto out; } dentry = fhp->fh_dentry; @@ -397,20 +397,28 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, iap->ia_valid &= ~ATTR_MODE; if (!iap->ia_valid) - goto out; + return 0; nfsd_sanitize_attrs(inode, iap); + if (check_guard && guardtime != inode->i_ctime.tv_sec) + return nfserr_notsync; + /* * The size case is special, it changes the file in addition to the - * attributes. + * attributes, and file systems don't expect it to be mixed with + * "random" attribute changes. We thus split out the size change + * into a separate call to ->setattr, and do the rest as a separate + * setattr call. */ - if (iap->ia_valid & ATTR_SIZE) { + if (size_change) { err = nfsd_get_write_access(rqstp, fhp, iap); if (err) - goto out; - size_change = 1; + return err; + } + fh_lock(fhp); + if (size_change) { /* * RFC5661, Section 18.30.4: * Changing the size of a file with SETATTR indirectly @@ -418,29 +426,36 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, * * (and similar for the older RFCs) */ - if (iap->ia_size != i_size_read(inode)) - iap->ia_valid |= ATTR_MTIME; - } + struct iattr size_attr = { + .ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME, + .ia_size = iap->ia_size, + }; - iap->ia_valid |= ATTR_CTIME; + host_err = notify_change(dentry, &size_attr, NULL); + if (host_err) + goto out_unlock; + iap->ia_valid &= ~ATTR_SIZE; - if (check_guard && guardtime != inode->i_ctime.tv_sec) { - err = nfserr_notsync; - goto out_put_write_access; + /* + * Avoid the additional setattr call below if the only other + * attribute that the client sends is the mtime, as we update + * it as part of the size change above. + */ + if ((iap->ia_valid & ~ATTR_MTIME) == 0) + goto out_unlock; } - fh_lock(fhp); + iap->ia_valid |= ATTR_CTIME; host_err = notify_change(dentry, iap, NULL); - fh_unlock(fhp); - err = nfserrno(host_err); -out_put_write_access: +out_unlock: + fh_unlock(fhp); if (size_change) put_write_access(inode); - if (!err) - err = nfserrno(commit_metadata(fhp)); out: - return err; + if (!host_err) + host_err = commit_metadata(fhp); + return nfserrno(host_err); } #if defined(CONFIG_NFSD_V4) diff --git a/fs/pnode.c b/fs/pnode.c index cbaa998ad625..1d16bb3bdf5e 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -324,6 +324,21 @@ out: return ret; } +static struct mount *find_topper(struct mount *mnt) +{ + /* If there is exactly one mount covering mnt completely return it. */ + struct mount *child; + + if (!list_is_singular(&mnt->mnt_mounts)) + return NULL; + + child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child); + if (child->mnt_mountpoint != mnt->mnt.mnt_root) + return NULL; + + return child; +} + /* * return true if the refcount is greater than count */ @@ -344,9 +359,8 @@ static inline int do_refcount_check(struct mount *mnt, int count) */ int propagate_mount_busy(struct mount *mnt, int refcnt) { - struct mount *m, *child; + struct mount *m, *child, *topper; struct mount *parent = mnt->mnt_parent; - int ret = 0; if (mnt == parent) return do_refcount_check(mnt, refcnt); @@ -361,12 +375,24 @@ int propagate_mount_busy(struct mount *mnt, int refcnt) for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint); - if (child && list_empty(&child->mnt_mounts) && - (ret = do_refcount_check(child, 1))) - break; + int count = 1; + child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); + if (!child) + continue; + + /* Is there exactly one mount on the child that covers + * it completely whose reference should be ignored? + */ + topper = find_topper(child); + if (topper) + count += 1; + else if (!list_empty(&child->mnt_mounts)) + continue; + + if (do_refcount_check(child, count)) + return 1; } - return ret; + return 0; } /* @@ -383,7 +409,7 @@ void propagate_mount_unlock(struct mount *mnt) for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint); + child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); if (child) child->mnt.mnt_flags &= ~MNT_LOCKED; } @@ -401,9 +427,11 @@ static void mark_umount_candidates(struct mount *mnt) for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - struct mount *child = __lookup_mnt_last(&m->mnt, + struct mount *child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); - if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) { + if (!child || (child->mnt.mnt_flags & MNT_UMOUNT)) + continue; + if (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m)) { SET_MNT_MARK(child); } } @@ -422,8 +450,8 @@ static void __propagate_umount(struct mount *mnt) for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - - struct mount *child = __lookup_mnt_last(&m->mnt, + struct mount *topper; + struct mount *child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); /* * umount the child only if the child has no children @@ -432,6 +460,15 @@ static void __propagate_umount(struct mount *mnt) if (!child || !IS_MNT_MARKED(child)) continue; CLEAR_MNT_MARK(child); + + /* If there is exactly one mount covering all of child + * replace child with that mount. + */ + topper = find_topper(child); + if (topper) + mnt_change_mountpoint(child->mnt_parent, child->mnt_mp, + topper); + if (list_empty(&child->mnt_mounts)) { list_del_init(&child->mnt_child); child->mnt.mnt_flags |= MNT_UMOUNT; diff --git a/fs/pnode.h b/fs/pnode.h index 3cb58c0cdcbc..f41fc9a6c48e 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -50,6 +50,8 @@ int get_dominating_id(struct mount *mnt, const struct path *root); unsigned int mnt_get_count(struct mount *mnt); void mnt_set_mountpoint(struct mount *, struct mountpoint *, struct mount *); +void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, + struct mount *mnt); struct mount *copy_tree(struct mount *, struct dentry *, int); bool is_path_reachable(struct mount *, struct dentry *, const struct path *root); diff --git a/fs/splice.c b/fs/splice.c index 0f77e9682857..8398974e1538 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -211,6 +211,7 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe, buf->len = spd->partial[page_nr].len; buf->private = spd->partial[page_nr].private; buf->ops = spd->ops; + buf->flags = 0; if (spd->flags & SPLICE_F_GIFT) buf->flags |= PIPE_BUF_FLAG_GIFT; diff --git a/include/dt-bindings/clock/msm-clocks-8996.h b/include/dt-bindings/clock/msm-clocks-8996.h index 22109a6766db..da794841d1eb 100644 --- a/include/dt-bindings/clock/msm-clocks-8996.h +++ b/include/dt-bindings/clock/msm-clocks-8996.h @@ -54,6 +54,8 @@ #define clk_ipa_clk 0xfa685cda #define clk_ln_bb_clk 0x3ab0b36d #define clk_ln_bb_a_clk 0xc7257ea8 +#define clk_ln_bb_clk_pin 0x1b1c476a +#define clk_ln_bb_a_clk_pin 0x9cbb5411 #define clk_mcd_ce1_clk 0xbb615d26 #define clk_pnoc_keepalive_a_clk 0xf8f91f0b #define clk_pnoc_msmbus_clk 0x38b95c77 diff --git a/include/dt-bindings/clock/msm-clocks-hwio-8996.h b/include/dt-bindings/clock/msm-clocks-hwio-8996.h index 10e25be91752..21dc1e6c55e3 100644 --- a/include/dt-bindings/clock/msm-clocks-hwio-8996.h +++ b/include/dt-bindings/clock/msm-clocks-hwio-8996.h @@ -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 @@ -42,6 +42,7 @@ #define RF_CLK1_ID 0x4 #define RF_CLK2_ID 0x5 #define LN_BB_CLK_ID 0x8 +#define LN_BB_CLK_PIN_ID 0x8 #define DIV_CLK1_ID 0xb #define DIV_CLK2_ID 0xc #define DIV_CLK3_ID 0xd diff --git a/include/linux/can/core.h b/include/linux/can/core.h index a0875001b13c..df08a41d5be5 100644 --- a/include/linux/can/core.h +++ b/include/linux/can/core.h @@ -45,10 +45,9 @@ struct can_proto { extern int can_proto_register(const struct can_proto *cp); extern void can_proto_unregister(const struct can_proto *cp); -extern int can_rx_register(struct net_device *dev, canid_t can_id, - canid_t mask, - void (*func)(struct sk_buff *, void *), - void *data, char *ident); +int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, + void (*func)(struct sk_buff *, void *), + void *data, char *ident, struct sock *sk); extern void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h index e55c08bc3a96..0abc56140c83 100644 --- a/include/linux/ceph/osdmap.h +++ b/include/linux/ceph/osdmap.h @@ -49,7 +49,7 @@ static inline bool ceph_can_shift_osds(struct ceph_pg_pool_info *pool) case CEPH_POOL_TYPE_EC: return false; default: - BUG_ON(1); + BUG(); } } diff --git a/include/linux/esoc_client.h b/include/linux/esoc_client.h index 43c03389ecac..8d13c88eda81 100644 --- a/include/linux/esoc_client.h +++ b/include/linux/esoc_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ struct esoc_desc { const char *name; const char *link; + const char *link_info; void *priv; }; diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index 9364ba71873e..6eb18a6d4e72 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -54,7 +54,8 @@ struct gpio_keys_platform_data { unsigned int rep:1; int (*enable)(struct device *dev); void (*disable)(struct device *dev); - const char *name; + const char *name; /* input device name */ + bool use_syscore; }; #endif diff --git a/include/linux/i2c/i2c-msm-v2.h b/include/linux/i2c/i2c-msm-v2.h index 54974c02725d..468a1d6fa58d 100644 --- a/include/linux/i2c/i2c-msm-v2.h +++ b/include/linux/i2c/i2c-msm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015,2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -552,6 +552,7 @@ struct i2c_msm_xfer { int msg_cnt; enum i2c_msm_xfer_mode_id mode_id; struct completion complete; + struct completion rx_complete; size_t rx_cnt; size_t tx_cnt; size_t rx_ovrhd_cnt; diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index d49e26c6cdc7..23e129ef6726 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -153,8 +153,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) #define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60) #define DMA_TLB_DSI_FLUSH (((u64)2) << 60) #define DMA_TLB_PSI_FLUSH (((u64)3) << 60) -#define DMA_TLB_IIRG(type) ((type >> 60) & 7) -#define DMA_TLB_IAIG(val) (((val) >> 57) & 7) +#define DMA_TLB_IIRG(type) ((type >> 60) & 3) +#define DMA_TLB_IAIG(val) (((val) >> 57) & 3) #define DMA_TLB_READ_DRAIN (((u64)1) << 49) #define DMA_TLB_WRITE_DRAIN (((u64)1) << 48) #define DMA_TLB_DID(id) (((u64)((id) & 0xffff)) << 32) @@ -164,9 +164,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) /* INVALID_DESC */ #define DMA_CCMD_INVL_GRANU_OFFSET 61 -#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3) -#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3) -#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3) +#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 4) +#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 4) +#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 4) #define DMA_ID_TLB_READ_DRAIN (((u64)1) << 7) #define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6) #define DMA_ID_TLB_DID(id) (((u64)((id & 0xffff) << 16))) @@ -316,8 +316,8 @@ enum { #define QI_DEV_EIOTLB_SIZE (((u64)1) << 11) #define QI_DEV_EIOTLB_GLOB(g) ((u64)g) #define QI_DEV_EIOTLB_PASID(p) (((u64)p) << 32) -#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 32) -#define QI_DEV_EIOTLB_QDEP(qd) (((qd) & 0x1f) << 16) +#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 16) +#define QI_DEV_EIOTLB_QDEP(qd) ((u64)((qd) & 0x1f) << 4) #define QI_DEV_EIOTLB_MAX_INVS 32 #define QI_PGRP_IDX(idx) (((u64)(idx)) << 55) diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 3f021dc5da8c..30201b9be7bc 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -83,6 +83,8 @@ struct nd_cmd_desc { struct nd_interleave_set { u64 cookie; + /* compatibility with initial buggy Linux implementation */ + u64 altcookie; }; struct nd_region_desc { diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index c15373894a42..b37dee3acaba 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -355,7 +355,8 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp) static inline int nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2) { - return fl1->fl_pid == fl2->fl_pid + return file_inode(fl1->fl_file) == file_inode(fl2->fl_file) + && fl1->fl_pid == fl2->fl_pid && fl1->fl_owner == fl2->fl_owner && fl1->fl_start == fl2->fl_start && fl1->fl_end == fl2->fl_end diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1acd6027f2ea..0a306b431ece 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1399,6 +1399,7 @@ enum netdev_priv_flags { * @mtu: Interface MTU value * @type: Interface hardware type * @hard_header_len: Maximum hardware header length. + * @min_header_len: Minimum hardware header length * * @needed_headroom: Extra headroom the hardware may need, but not in all * cases can this be guaranteed @@ -1619,6 +1620,7 @@ struct net_device { unsigned int mtu; unsigned short type; unsigned short hard_header_len; + unsigned short min_header_len; unsigned short needed_headroom; unsigned short needed_tailroom; @@ -2541,6 +2543,8 @@ static inline bool dev_validate_header(const struct net_device *dev, { if (likely(len >= dev->hard_header_len)) return true; + if (len < dev->min_header_len) + return false; if (capable(CAP_SYS_RAWIO)) { memset(ll_header + len, 0, dev->hard_header_len - len); diff --git a/drivers/power/supply/qcom/pmic-voter.h b/include/linux/pmic-voter.h index f202bf704055..f202bf704055 100644 --- a/drivers/power/supply/qcom/pmic-voter.h +++ b/include/linux/pmic-voter.h diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 1effc355d7d0..864f7f6a0d01 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -217,6 +217,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_DP_DM, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, POWER_SUPPLY_PROP_CURRENT_QNOVO, POWER_SUPPLY_PROP_VOLTAGE_QNOVO, POWER_SUPPLY_PROP_RERUN_AICL, diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h index 4023e3a683d3..a0e2283ef4c9 100644 --- a/include/linux/qpnp/qpnp-revid.h +++ b/include/linux/qpnp/qpnp-revid.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -181,6 +181,7 @@ #define PM660L_SUBTYPE 0x1A #define PM660_SUBTYPE 0x1B +/* PMI8998 REV_ID */ #define PMI8998_V1P0_REV1 0x00 #define PMI8998_V1P0_REV2 0x00 #define PMI8998_V1P0_REV3 0x00 @@ -196,6 +197,26 @@ #define PMI8998_V2P0_REV3 0x00 #define PMI8998_V2P0_REV4 0x02 +/* PM660 REV_ID */ +#define PM660_V1P0_REV1 0x00 +#define PM660_V1P0_REV2 0x00 +#define PM660_V1P0_REV3 0x00 +#define PM660_V1P0_REV4 0x01 + +#define PM660_V1P1_REV1 0x00 +#define PM660_V1P1_REV2 0x00 +#define PM660_V1P1_REV3 0x01 +#define PM660_V1P1_REV4 0x01 + +/* PMI8998 FAB_ID */ +#define PMI8998_FAB_ID_SMIC 0x11 +#define PMI8998_FAB_ID_GF 0x30 + +/* PM660 FAB_ID */ +#define PM660_FAB_ID_GF 0x0 +#define PM660_FAB_ID_TSMC 0x2 +#define PM660_FAB_ID_MX 0x3 + /* PM8005 */ #define PM8005_SUBTYPE 0x18 diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h index 623fbfce6c67..1e677f95a375 100644 --- a/include/media/msmb_pproc.h +++ b/include/media/msmb_pproc.h @@ -5,6 +5,8 @@ #include <linux/compat.h> +#define MSM_OUTPUT_BUF_CNT 8 + #ifdef CONFIG_COMPAT struct msm_cpp_frame_info32_t { int32_t frame_id; @@ -26,7 +28,7 @@ struct msm_cpp_frame_info32_t { uint32_t feature_mask; uint8_t we_disable; struct msm_cpp_buffer_info_t input_buffer_info; - struct msm_cpp_buffer_info_t output_buffer_info[8]; + struct msm_cpp_buffer_info_t output_buffer_info[MSM_OUTPUT_BUF_CNT]; struct msm_cpp_buffer_info_t duplicate_buffer_info; struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2]; uint32_t reserved; diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 3ebb168b9afc..a34b141f125f 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -309,6 +309,10 @@ static inline int cipso_v4_validate(const struct sk_buff *skb, } for (opt_iter = 6; opt_iter < opt_len;) { + if (opt_iter + 1 == opt_len) { + err_offset = opt_iter; + goto out; + } tag_len = opt[opt_iter + 1]; if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) { err_offset = opt_iter + 1; diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index 301969552d0a..b43e64d69734 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -138,12 +138,12 @@ struct ib_sa_path_rec { union ib_gid sgid; __be16 dlid; __be16 slid; - int raw_traffic; + u8 raw_traffic; /* reserved */ __be32 flow_label; u8 hop_limit; u8 traffic_class; - int reversible; + u8 reversible; u8 numb_path; __be16 pkey; __be16 qos_class; @@ -204,7 +204,7 @@ struct ib_sa_mcmember_rec { u8 hop_limit; u8 scope; u8 join_state; - int proxy_join; + u8 proxy_join; }; /* Service Record Component Mask Sec 15.2.5.14 Ver 1.1 */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c37b22101473..5dfc8d01b95c 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -311,6 +311,7 @@ extern void scsi_remove_device(struct scsi_device *); extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); void scsi_attach_vpd(struct scsi_device *sdev); +extern struct scsi_device *scsi_device_from_queue(struct request_queue *q); extern int scsi_device_get(struct scsi_device *); extern void scsi_device_put(struct scsi_device *); extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *, diff --git a/include/soc/at91/at91sam9_ddrsdr.h b/include/soc/at91/at91sam9_ddrsdr.h index dc10c52e0e91..393362bdb860 100644 --- a/include/soc/at91/at91sam9_ddrsdr.h +++ b/include/soc/at91/at91sam9_ddrsdr.h @@ -81,6 +81,7 @@ #define AT91_DDRSDRC_LPCB_POWER_DOWN 2 #define AT91_DDRSDRC_LPCB_DEEP_POWER_DOWN 3 #define AT91_DDRSDRC_CLKFR (1 << 2) /* Clock Frozen */ +#define AT91_DDRSDRC_LPDDR2_PWOFF (1 << 3) /* LPDDR Power Off */ #define AT91_DDRSDRC_PASR (7 << 4) /* Partial Array Self Refresh */ #define AT91_DDRSDRC_TCSR (3 << 8) /* Temperature Compensated Self Refresh */ #define AT91_DDRSDRC_DS (3 << 10) /* Drive Strength */ @@ -96,7 +97,9 @@ #define AT91_DDRSDRC_MD_SDR 0 #define AT91_DDRSDRC_MD_LOW_POWER_SDR 1 #define AT91_DDRSDRC_MD_LOW_POWER_DDR 3 +#define AT91_DDRSDRC_MD_LPDDR3 5 #define AT91_DDRSDRC_MD_DDR2 6 /* [SAM9 Only] */ +#define AT91_DDRSDRC_MD_LPDDR2 7 #define AT91_DDRSDRC_DBW (1 << 4) /* Data Bus Width */ #define AT91_DDRSDRC_DBW_32BITS (0 << 4) #define AT91_DDRSDRC_DBW_16BITS (1 << 4) diff --git a/include/soc/qcom/clock-alpha-pll.h b/include/soc/qcom/clock-alpha-pll.h index 0b5329ba817c..acffe33dc4f3 100644 --- a/include/soc/qcom/clock-alpha-pll.h +++ b/include/soc/qcom/clock-alpha-pll.h @@ -79,6 +79,7 @@ struct alpha_pll_clk { * that the workaround is required. */ bool offline_bit_workaround; + bool no_irq_dis; bool is_fabia; unsigned long min_supported_freq; struct clk c; diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 06c273252484..a5ba1496eef7 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -443,6 +443,11 @@ struct adm_param_data_v5 { */ } __packed; +#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213 +#define ASM_STREAM_PP_EVENT 0x00013214 +#define DSP_STREAM_CMD "ADSP Stream Cmd" +#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event" + /* set customized mixing on matrix mixer */ #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344 struct adm_cmd_set_pspd_mtmx_strtr_params_v5 { diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index d077827647b5..29707b26644a 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -618,6 +618,9 @@ int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp); int q6asm_send_audio_effects_params(struct audio_client *ac, char *params, uint32_t params_length); +int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, + void *param, uint32_t params_length); + /* Client can set the IO mode to either AIO/SIO mode */ int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 6afc6f388edf..ed66414b91f0 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -544,6 +544,7 @@ struct se_node_acl { /* Used to signal demo mode created ACL, disabled by default */ bool dynamic_node_acl; bool acl_stop:1; + bool dynamic_stop; u32 queue_depth; u32 acl_index; enum target_prot_type saved_prot_type; @@ -739,6 +740,7 @@ struct se_lun { struct config_group lun_group; struct se_port_stat_grps port_stat_grps; struct completion lun_ref_comp; + struct completion lun_shutdown_comp; struct percpu_ref lun_ref; struct list_head lun_dev_link; struct hlist_node link; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index ce9ea736f1d7..97069ecabe49 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -168,6 +168,8 @@ void core_allocate_nexus_loss_ua(struct se_node_acl *acl); struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); +bool target_tpg_has_node_acl(struct se_portal_group *tpg, + const char *); struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, unsigned char *); int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h index 14e49c798135..b35533b94277 100644 --- a/include/trace/events/syscalls.h +++ b/include/trace/events/syscalls.h @@ -1,5 +1,6 @@ #undef TRACE_SYSTEM #define TRACE_SYSTEM raw_syscalls +#undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE syscalls #if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ) diff --git a/include/uapi/linux/rmnet_data.h b/include/uapi/linux/rmnet_data.h index 8cfe0270ef4f..7ddfa20cec32 100644 --- a/include/uapi/linux/rmnet_data.h +++ b/include/uapi/linux/rmnet_data.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -223,8 +223,19 @@ enum rmnet_netlink_message_types_e { * uint32_t MAP Flow Handle * Returns: status code */ - RMNET_NETLINK_DEL_VND_TC_FLOW + RMNET_NETLINK_DEL_VND_TC_FLOW, + + /* + * RMNET_NETLINK_NEW_VND_WITH_NAME - Creates a new virtual network + * device node with the specified + * device name + * Args: int32_t node number + * char[] vnd_name - Use as name + * Returns: status code + */ + RMNET_NETLINK_NEW_VND_WITH_NAME }; +#define RMNET_NETLINK_NEW_VND_WITH_NAME RMNET_NETLINK_NEW_VND_WITH_NAME enum rmnet_config_endpoint_modes_e { /* Pass the frame up the stack with no modifications to skb->dev */ diff --git a/ipc/shm.c b/ipc/shm.c index 88a6f1e78066..09267be8d27b 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1083,8 +1083,8 @@ out_unlock1: * "raddr" thing points to kernel space, and there has to be a wrapper around * this. */ -long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, - unsigned long shmlba) +long do_shmat(int shmid, char __user *shmaddr, int shmflg, + ulong *raddr, unsigned long shmlba) { struct shmid_kernel *shp; unsigned long addr; @@ -1105,8 +1105,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, goto out; else if ((addr = (ulong)shmaddr)) { if (addr & (shmlba - 1)) { - if (shmflg & SHM_RND) - addr &= ~(shmlba - 1); /* round down */ + /* + * Round down to the nearest multiple of shmlba. + * For sane do_mmap_pgoff() parameters, avoid + * round downs that trigger nil-page and MAP_FIXED. + */ + if ((shmflg & SHM_RND) && addr >= shmlba) + addr &= ~(shmlba - 1); else #ifndef __ARCH_FORCE_SHMLBA if (addr & ~PAGE_MASK) diff --git a/kernel/futex.c b/kernel/futex.c index e8af73cc51a7..beb042dcc332 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -3199,4 +3199,4 @@ static int __init futex_init(void) return 0; } -__initcall(futex_init); +core_initcall(futex_init); diff --git a/kernel/membarrier.c b/kernel/membarrier.c index 536c727a56e9..9f9284f37f8d 100644 --- a/kernel/membarrier.c +++ b/kernel/membarrier.c @@ -16,6 +16,7 @@ #include <linux/syscalls.h> #include <linux/membarrier.h> +#include <linux/tick.h> /* * Bitmask made from a "or" of all commands within enum membarrier_cmd, @@ -51,6 +52,9 @@ */ SYSCALL_DEFINE2(membarrier, int, cmd, int, flags) { + /* MEMBARRIER_CMD_SHARED is not compatible with nohz_full. */ + if (tick_nohz_full_enabled()) + return -ENOSYS; if (unlikely(flags)) return -EINVAL; switch (cmd) { diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 7b884dc55bd0..9fcb521fab0e 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1440,7 +1440,7 @@ static void call_console_drivers(int level, { struct console *con; - trace_console(text, len); + trace_console_rcuidle(text, len); if (level >= console_loglevel && !ignore_loglevel) return; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 312ffdad034a..1017a3f77391 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -88,6 +88,7 @@ #include "sched.h" #include "../workqueue_internal.h" #include "../smpboot.h" +#include "../time/tick-internal.h" #define CREATE_TRACE_POINTS #include <trace/events/sched.h> @@ -3260,7 +3261,8 @@ void scheduler_tick(void) if (curr->sched_class == &fair_sched_class) check_for_migration(rq, curr); - core_ctl_check(wallclock); + if (cpu == tick_do_timer_cpu) + core_ctl_check(wallclock); } #ifdef CONFIG_NO_HZ_FULL diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index 983159cc0646..1dde338d30f2 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -653,6 +653,9 @@ int core_ctl_set_boost(bool boost) int ret = 0; bool boost_state_changed = false; + if (unlikely(!initialized)) + return 0; + spin_lock_irqsave(&state_lock, flags); for_each_cluster(cluster, index) { if (cluster->is_big_cluster) { @@ -931,6 +934,42 @@ static struct notifier_block __refdata cpu_notifier = { /* ============================ init code ============================== */ +static cpumask_var_t core_ctl_disable_cpumask; +static bool core_ctl_disable_cpumask_present; + +static int __init core_ctl_disable_setup(char *str) +{ + if (!*str) + return -EINVAL; + + alloc_bootmem_cpumask_var(&core_ctl_disable_cpumask); + + if (cpulist_parse(str, core_ctl_disable_cpumask) < 0) { + free_bootmem_cpumask_var(core_ctl_disable_cpumask); + return -EINVAL; + } + + core_ctl_disable_cpumask_present = true; + pr_info("disable_cpumask=%*pbl\n", + cpumask_pr_args(core_ctl_disable_cpumask)); + + return 0; +} +early_param("core_ctl_disable_cpumask", core_ctl_disable_setup); + +static bool should_skip(const struct cpumask *mask) +{ + if (!core_ctl_disable_cpumask_present) + return false; + + /* + * We operate on a cluster basis. Disable the core_ctl for + * a cluster, if all of it's cpus are specified in + * core_ctl_disable_cpumask + */ + return cpumask_subset(mask, core_ctl_disable_cpumask); +} + static struct cluster_data *find_cluster_by_first_cpu(unsigned int first_cpu) { unsigned int i; @@ -952,6 +991,9 @@ static int cluster_init(const struct cpumask *mask) unsigned int cpu; struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + if (should_skip(mask)) + return 0; + if (find_cluster_by_first_cpu(first_cpu)) return 0; @@ -1052,6 +1094,9 @@ static int __init core_ctl_init(void) { unsigned int cpu; + if (should_skip(cpu_possible_mask)) + return 0; + core_ctl_check_interval = (rq_avg_period_ms - RQ_AVG_TOLERANCE) * NSEC_PER_MSEC; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 9ef80bf441b3..a988d4ef39da 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -757,15 +757,20 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) if (!bdi->wb_congested) return -ENOMEM; + atomic_set(&bdi->wb_congested->refcnt, 1); + err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); if (err) { - kfree(bdi->wb_congested); + wb_congested_put(bdi->wb_congested); return err; } return 0; } -static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { } +static void cgwb_bdi_destroy(struct backing_dev_info *bdi) +{ + wb_congested_put(bdi->wb_congested); +} #endif /* CONFIG_CGROUP_WRITEBACK */ diff --git a/mm/filemap.c b/mm/filemap.c index 33be70a2ded3..8b2cf0f6a529 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -867,9 +867,12 @@ void page_endio(struct page *page, int rw, int err) unlock_page(page); } else { /* rw == WRITE */ if (err) { + struct address_space *mapping; + SetPageError(page); - if (page->mapping) - mapping_set_error(page->mapping, err); + mapping = page_mapping(page); + if (mapping) + mapping_set_error(mapping, err); } end_page_writeback(page); } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 43eefe9d834c..e25b93a4267d 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4150,24 +4150,6 @@ static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n) atomic_add(n, &memcg->id.ref); } -static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg) -{ - while (!atomic_inc_not_zero(&memcg->id.ref)) { - /* - * The root cgroup cannot be destroyed, so it's refcount must - * always be >= 1. - */ - if (WARN_ON_ONCE(memcg == root_mem_cgroup)) { - VM_BUG_ON(1); - break; - } - memcg = parent_mem_cgroup(memcg); - if (!memcg) - memcg = root_mem_cgroup; - } - return memcg; -} - static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n) { if (atomic_sub_and_test(n, &memcg->id.ref)) { @@ -5751,6 +5733,24 @@ static int __init mem_cgroup_init(void) subsys_initcall(mem_cgroup_init); #ifdef CONFIG_MEMCG_SWAP +static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg) +{ + while (!atomic_inc_not_zero(&memcg->id.ref)) { + /* + * The root cgroup cannot be destroyed, so it's refcount must + * always be >= 1. + */ + if (WARN_ON_ONCE(memcg == root_mem_cgroup)) { + VM_BUG_ON(1); + break; + } + memcg = parent_mem_cgroup(memcg); + if (!memcg) + memcg = root_mem_cgroup; + } + return memcg; +} + /** * mem_cgroup_swapout - transfer a memsw charge to swap * @page: page whose memsw charge to transfer diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fbed8bb17388..28f60d9ea074 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2569,7 +2569,7 @@ static bool zone_local(struct zone *local_zone, struct zone *zone) static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone) { - return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) < + return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <= RECLAIM_DISTANCE; } #else /* CONFIG_NUMA */ diff --git a/net/can/af_can.c b/net/can/af_can.c index 166d436196c1..928f58064098 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -445,6 +445,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, * @func: callback function on filter match * @data: returned parameter for callback function * @ident: string for calling module identification + * @sk: socket pointer (might be NULL) * * Description: * Invokes the callback function with the received sk_buff and the given @@ -468,7 +469,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, */ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, void (*func)(struct sk_buff *, void *), void *data, - char *ident) + char *ident, struct sock *sk) { struct receiver *r; struct hlist_head *rl; @@ -496,6 +497,7 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, r->func = func; r->data = data; r->ident = ident; + r->sk = sk; hlist_add_head_rcu(&r->list, rl); d->entries++; @@ -520,8 +522,11 @@ EXPORT_SYMBOL(can_rx_register); static void can_rx_delete_receiver(struct rcu_head *rp) { struct receiver *r = container_of(rp, struct receiver, rcu); + struct sock *sk = r->sk; kmem_cache_free(rcv_cache, r); + if (sk) + sock_put(sk); } /** @@ -596,8 +601,11 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, spin_unlock(&can_rcvlists_lock); /* schedule the receiver item for deletion */ - if (r) + if (r) { + if (r->sk) + sock_hold(r->sk); call_rcu(&r->rcu, can_rx_delete_receiver); + } } EXPORT_SYMBOL(can_rx_unregister); diff --git a/net/can/af_can.h b/net/can/af_can.h index fca0fe9fc45a..b86f5129e838 100644 --- a/net/can/af_can.h +++ b/net/can/af_can.h @@ -50,13 +50,14 @@ struct receiver { struct hlist_node list; - struct rcu_head rcu; canid_t can_id; canid_t mask; unsigned long matches; void (*func)(struct sk_buff *, void *); void *data; char *ident; + struct sock *sk; + struct rcu_head rcu; }; #define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS) diff --git a/net/can/bcm.c b/net/can/bcm.c index 24d66c1cc0cd..4ccfd356baed 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1179,7 +1179,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, err = can_rx_register(dev, op->can_id, REGMASK(op->can_id), bcm_rx_handler, op, - "bcm"); + "bcm", sk); op->rx_reg_dev = dev; dev_put(dev); @@ -1188,7 +1188,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, } else err = can_rx_register(NULL, op->can_id, REGMASK(op->can_id), - bcm_rx_handler, op, "bcm"); + bcm_rx_handler, op, "bcm", sk); if (err) { /* this bcm rx op is broken -> remove it */ list_del(&op->list); diff --git a/net/can/gw.c b/net/can/gw.c index 455168718c2e..77c8af4047ef 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -442,7 +442,7 @@ static inline int cgw_register_filter(struct cgw_job *gwj) { return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id, gwj->ccgw.filter.can_mask, can_can_gw_rcv, - gwj, "gw"); + gwj, "gw", NULL); } static inline void cgw_unregister_filter(struct cgw_job *gwj) diff --git a/net/can/raw.c b/net/can/raw.c index 56af689ca999..e9403a26a1d5 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -190,7 +190,7 @@ static int raw_enable_filters(struct net_device *dev, struct sock *sk, for (i = 0; i < count; i++) { err = can_rx_register(dev, filter[i].can_id, filter[i].can_mask, - raw_rcv, sk, "raw"); + raw_rcv, sk, "raw", sk); if (err) { /* clean up successfully registered filters */ while (--i >= 0) @@ -211,7 +211,7 @@ static int raw_enable_errfilter(struct net_device *dev, struct sock *sk, if (err_mask) err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG, - raw_rcv, sk, "raw"); + raw_rcv, sk, "raw", sk); return err; } diff --git a/net/core/dev.c b/net/core/dev.c index 1d24d5e54ac0..51aed87e8eec 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1678,24 +1678,19 @@ EXPORT_SYMBOL_GPL(net_dec_ingress_queue); static struct static_key netstamp_needed __read_mostly; #ifdef HAVE_JUMP_LABEL -/* We are not allowed to call static_key_slow_dec() from irq context - * If net_disable_timestamp() is called from irq context, defer the - * static_key_slow_dec() calls. - */ static atomic_t netstamp_needed_deferred; -#endif - -void net_enable_timestamp(void) +static void netstamp_clear(struct work_struct *work) { -#ifdef HAVE_JUMP_LABEL int deferred = atomic_xchg(&netstamp_needed_deferred, 0); - if (deferred) { - while (--deferred) - static_key_slow_dec(&netstamp_needed); - return; - } + while (deferred--) + static_key_slow_dec(&netstamp_needed); +} +static DECLARE_WORK(netstamp_work, netstamp_clear); #endif + +void net_enable_timestamp(void) +{ static_key_slow_inc(&netstamp_needed); } EXPORT_SYMBOL(net_enable_timestamp); @@ -1703,12 +1698,12 @@ EXPORT_SYMBOL(net_enable_timestamp); void net_disable_timestamp(void) { #ifdef HAVE_JUMP_LABEL - if (in_interrupt()) { - atomic_inc(&netstamp_needed_deferred); - return; - } -#endif + /* net_disable_timestamp() can be called from non process context */ + atomic_inc(&netstamp_needed_deferred); + schedule_work(&netstamp_work); +#else static_key_slow_dec(&netstamp_needed); +#endif } EXPORT_SYMBOL(net_disable_timestamp); diff --git a/net/dccp/input.c b/net/dccp/input.c index 3bd14e885396..dbe2573f6ba1 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -606,7 +606,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (inet_csk(sk)->icsk_af_ops->conn_request(sk, skb) < 0) return 1; - goto discard; + consume_skb(skb); + return 0; } if (dh->dccph_type == DCCP_PKT_RESET) goto discard; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index de85d4e1cf43..52dcd414c2af 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -353,6 +353,7 @@ void ether_setup(struct net_device *dev) dev->header_ops = ð_header_ops; dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; + dev->min_header_len = ETH_HLEN; dev->mtu = ETH_DATA_LEN; dev->addr_len = ETH_ALEN; dev->tx_queue_len = 1000; /* Ethernet wants good queues */ diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index bdb2a07ec363..6cc3e1d602fb 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1657,6 +1657,10 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) goto validate_return_locked; } + if (opt_iter + 1 == opt_len) { + err_offset = opt_iter; + goto validate_return_locked; + } tag_len = tag[1]; if (tag_len > (opt_len - opt_iter)) { err_offset = opt_iter + 1; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 9ce202549e7a..f300d1cbfa91 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -105,10 +105,10 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, if (skb->ip_summed != CHECKSUM_COMPLETE) return; - if (offset != 0) - csum = csum_sub(csum, - csum_partial(skb->data + tlen, - offset, 0)); + if (offset != 0) { + int tend_off = skb_transport_offset(skb) + tlen; + csum = csum_sub(csum, skb_checksum(skb, tend_off, offset, 0)); + } put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum); } @@ -1192,7 +1192,14 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) pktinfo->ipi_ifindex = 0; pktinfo->ipi_spec_dst.s_addr = 0; } - skb_dst_drop(skb); + /* We need to keep the dst for __ip_options_echo() + * We could restrict the test to opt.ts_needtime || opt.srr, + * but the following is good enough as IP options are not often used. + */ + if (unlikely(IPCB(skb)->opt.optlen)) + skb_dst_force(skb); + else + skb_dst_drop(skb); } int ip_setsockopt(struct sock *sk, int level, diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index e29249bc23b8..3a2b21e22629 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -645,6 +645,8 @@ static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, { struct sk_buff *skb = skb_peek(&sk->sk_write_queue); + if (!skb) + return 0; pfh->wcheck = csum_partial((char *)&pfh->icmph, sizeof(struct icmphdr), pfh->wcheck); pfh->icmph.checksum = csum_fold(pfh->wcheck); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 676566faf649..4ab7735e43ab 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -789,6 +789,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, ret = -EAGAIN; break; } + /* if __tcp_splice_read() got nothing while we have + * an skb in receive queue, we do not want to loop. + * This might happen with URG data. + */ + if (!skb_queue_empty(&sk->sk_receive_queue)) + break; sk_wait_data(sk, &timeo, NULL); if (signal_pending(current)) { ret = sock_intr_errno(timeo); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ca3731721d81..8a62ad0c850b 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2383,9 +2383,11 @@ u32 __tcp_select_window(struct sock *sk) int full_space = min_t(int, tp->window_clamp, allowed_space); int window; - if (mss > full_space) + if (unlikely(mss > full_space)) { mss = full_space; - + if (mss <= 0) + return 0; + } if (free_space < (full_space >> 1)) { icsk->icsk_ack.quick = 0; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index eba61b42cd42..ab0efaca4a78 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -55,6 +55,7 @@ #include <net/ip6_fib.h> #include <net/ip6_route.h> #include <net/ip6_tunnel.h> +#include <net/gre.h> static bool log_ecn_error = true; @@ -367,35 +368,37 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { - const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data; - __be16 *p = (__be16 *)(skb->data + offset); - int grehlen = offset + 4; + const struct gre_base_hdr *greh; + const struct ipv6hdr *ipv6h; + int grehlen = sizeof(*greh); struct ip6_tnl *t; + int key_off = 0; __be16 flags; + __be32 key; - flags = p[0]; - if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { - if (flags&(GRE_VERSION|GRE_ROUTING)) - return; - if (flags&GRE_KEY) { - grehlen += 4; - if (flags&GRE_CSUM) - grehlen += 4; - } + if (!pskb_may_pull(skb, offset + grehlen)) + return; + greh = (const struct gre_base_hdr *)(skb->data + offset); + flags = greh->flags; + if (flags & (GRE_VERSION | GRE_ROUTING)) + return; + if (flags & GRE_CSUM) + grehlen += 4; + if (flags & GRE_KEY) { + key_off = grehlen + offset; + grehlen += 4; } - /* If only 8 bytes returned, keyed message will be dropped here */ - if (!pskb_may_pull(skb, grehlen)) + if (!pskb_may_pull(skb, offset + grehlen)) return; ipv6h = (const struct ipv6hdr *)skb->data; - p = (__be16 *)(skb->data + offset); + greh = (const struct gre_base_hdr *)(skb->data + offset); + key = key_off ? *(__be32 *)(skb->data + key_off) : 0; t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, - flags & GRE_KEY ? - *(((__be32 *)p) + (grehlen / 4) - 1) : 0, - p[1]); + key, greh->protocol); if (!t) return; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index c9bd1ee1f145..8b11a49c7dd7 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -479,18 +479,19 @@ ip6_tnl_dev_uninit(struct net_device *dev) __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) { - const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; - __u8 nexthdr = ipv6h->nexthdr; - __u16 off = sizeof(*ipv6h); + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw; + unsigned int nhoff = raw - skb->data; + unsigned int off = nhoff + sizeof(*ipv6h); + u8 next, nexthdr = ipv6h->nexthdr; while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) { - __u16 optlen = 0; struct ipv6_opt_hdr *hdr; - if (raw + off + sizeof(*hdr) > skb->data && - !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr))) + u16 optlen; + + if (!pskb_may_pull(skb, off + sizeof(*hdr))) break; - hdr = (struct ipv6_opt_hdr *) (raw + off); + hdr = (struct ipv6_opt_hdr *)(skb->data + off); if (nexthdr == NEXTHDR_FRAGMENT) { struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr; if (frag_hdr->frag_off) @@ -501,20 +502,29 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) } else { optlen = ipv6_optlen(hdr); } + /* cache hdr->nexthdr, since pskb_may_pull() might + * invalidate hdr + */ + next = hdr->nexthdr; if (nexthdr == NEXTHDR_DEST) { - __u16 i = off + 2; + u16 i = 2; + + /* Remember : hdr is no longer valid at this point. */ + if (!pskb_may_pull(skb, off + optlen)) + break; + while (1) { struct ipv6_tlv_tnl_enc_lim *tel; /* No more room for encapsulation limit */ - if (i + sizeof (*tel) > off + optlen) + if (i + sizeof(*tel) > optlen) break; - tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i]; + tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i); /* return index of option if found and valid */ if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT && tel->length == 1) - return i; + return i + off - nhoff; /* else jump to next option */ if (tel->type) i += tel->length + 2; @@ -522,7 +532,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) i++; } } - nexthdr = hdr->nexthdr; + nexthdr = next; off += optlen; } return 0; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 3da2b16356eb..184f0fe35dc6 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1389,6 +1389,7 @@ static int ipip6_tunnel_init(struct net_device *dev) tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst); if (!tunnel->dst_cache) { free_percpu(dev->tstats); + dev->tstats = NULL; return -ENOMEM; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a6079e7a6c6b..108b39967694 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -976,6 +976,16 @@ drop: return 0; /* don't send reset */ } +static void tcp_v6_restore_cb(struct sk_buff *skb) +{ + /* We need to move header back to the beginning if xfrm6_policy_check() + * and tcp_v6_fill_cb() are going to be called again. + * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. + */ + memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, + sizeof(struct inet6_skb_parm)); +} + static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, struct request_sock *req, struct dst_entry *dst, @@ -1165,8 +1175,10 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * sk_gfp_atomic(sk, GFP_ATOMIC)); consume_skb(ireq->pktopts); ireq->pktopts = NULL; - if (newnp->pktoptions) + if (newnp->pktoptions) { + tcp_v6_restore_cb(newnp->pktoptions); skb_set_owner_r(newnp->pktoptions, newsk); + } } } @@ -1181,16 +1193,6 @@ out: return NULL; } -static void tcp_v6_restore_cb(struct sk_buff *skb) -{ - /* We need to move header back to the beginning if xfrm6_policy_check() - * and tcp_v6_fill_cb() are going to be called again. - * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. - */ - memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, - sizeof(struct inet6_skb_parm)); -} - /* The socket must have it's spinlock held when we get * here, unless it is a TCP_LISTEN socket. * diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c index acbe61c7e683..160dc89335e2 100644 --- a/net/irda/irqueue.c +++ b/net/irda/irqueue.c @@ -383,9 +383,6 @@ EXPORT_SYMBOL(hashbin_new); * for deallocating this structure if it's complex. If not the user can * just supply kfree, which should take care of the job. */ -#ifdef CONFIG_LOCKDEP -static int hashbin_lock_depth = 0; -#endif int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) { irda_queue_t* queue; @@ -396,22 +393,27 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;); /* Synchronize */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_lock_irqsave_nested(&hashbin->hb_spinlock, flags, - hashbin_lock_depth++); - } + if (hashbin->hb_type & HB_LOCK) + spin_lock_irqsave(&hashbin->hb_spinlock, flags); /* * Free the entries in the hashbin, TODO: use hashbin_clear when * it has been shown to work */ for (i = 0; i < HASHBIN_SIZE; i ++ ) { - queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]); - while (queue ) { - if (free_func) - (*free_func)(queue); - queue = dequeue_first( - (irda_queue_t**) &hashbin->hb_queue[i]); + while (1) { + queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]); + + if (!queue) + break; + + if (free_func) { + if (hashbin->hb_type & HB_LOCK) + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + free_func(queue); + if (hashbin->hb_type & HB_LOCK) + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } } } @@ -420,12 +422,8 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) hashbin->magic = ~HB_MAGIC; /* Release lock */ - if ( hashbin->hb_type & HB_LOCK) { + if (hashbin->hb_type & HB_LOCK) spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); -#ifdef CONFIG_LOCKDEP - hashbin_lock_depth--; -#endif - } /* * Free the hashbin structure diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 5871537af387..763e8e241ce3 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -273,6 +273,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops); void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); +int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg); /* Session reference counts. Incremented when code obtains a reference * to a session. diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index d0e906d39642..445b7cd0826a 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <asm/ioctls.h> #include <linux/icmp.h> #include <linux/module.h> #include <linux/skbuff.h> @@ -555,6 +556,30 @@ out: return err ? err : copied; } +int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + struct sk_buff *skb; + int amount; + + switch (cmd) { + case SIOCOUTQ: + amount = sk_wmem_alloc_get(sk); + break; + case SIOCINQ: + spin_lock_bh(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + amount = skb ? skb->len : 0; + spin_unlock_bh(&sk->sk_receive_queue.lock); + break; + + default: + return -ENOIOCTLCMD; + } + + return put_user(amount, (int __user *)arg); +} +EXPORT_SYMBOL(l2tp_ioctl); + static struct proto l2tp_ip_prot = { .name = "L2TP/IP", .owner = THIS_MODULE, @@ -563,7 +588,7 @@ static struct proto l2tp_ip_prot = { .bind = l2tp_ip_bind, .connect = l2tp_ip_connect, .disconnect = l2tp_ip_disconnect, - .ioctl = udp_ioctl, + .ioctl = l2tp_ioctl, .destroy = l2tp_ip_destroy_sock, .setsockopt = ip_setsockopt, .getsockopt = ip_getsockopt, diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 0289208b0346..c8f483cd2ca9 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -715,7 +715,7 @@ static struct proto l2tp_ip6_prot = { .bind = l2tp_ip6_bind, .connect = l2tp_ip6_connect, .disconnect = l2tp_ip6_disconnect, - .ioctl = udp_ioctl, + .ioctl = l2tp_ioctl, .destroy = l2tp_ip6_destroy_sock, .setsockopt = ipv6_setsockopt, .getsockopt = ipv6_getsockopt, diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 3e821daf9dd4..8bc5a1bd2d45 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -821,7 +821,10 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb) * another trick required to cope with how the PROCOM state * machine works. -acme */ + skb_orphan(skb); + sock_hold(sk); skb->sk = sk; + skb->destructor = sock_efree; } if (!sock_owned_by_user(sk)) llc_conn_rcv(sk, skb); diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index d0e1e804ebd7..5404d0d195cc 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -290,7 +290,10 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb, ev->type = LLC_SAP_EV_TYPE_PDU; ev->reason = 0; + skb_orphan(skb); + sock_hold(sk); skb->sk = sk; + skb->destructor = sock_efree; llc_sap_state_process(sap, skb); } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 00a43a70e1fc..0402fa45b343 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -168,6 +168,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) break; } + flush_delayed_work(&sdata->dec_tailroom_needed_wk); drv_remove_interface(local, sdata); } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f223d1c80ccf..d805cd577a60 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1497,6 +1497,8 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po) f->arr[f->num_members] = sk; smp_wmb(); f->num_members++; + if (f->num_members == 1) + dev_add_pack(&f->prot_hook); spin_unlock(&f->lock); } @@ -1513,6 +1515,8 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po) BUG_ON(i >= f->num_members); f->arr[i] = f->arr[f->num_members - 1]; f->num_members--; + if (f->num_members == 0) + __dev_remove_pack(&f->prot_hook); spin_unlock(&f->lock); } @@ -1623,6 +1627,7 @@ static void fanout_release_data(struct packet_fanout *f) static int fanout_add(struct sock *sk, u16 id, u16 type_flags) { + struct packet_rollover *rollover = NULL; struct packet_sock *po = pkt_sk(sk); struct packet_fanout *f, *match; u8 type = type_flags & 0xff; @@ -1645,23 +1650,28 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) return -EINVAL; } + mutex_lock(&fanout_mutex); + + err = -EINVAL; if (!po->running) - return -EINVAL; + goto out; + err = -EALREADY; if (po->fanout) - return -EALREADY; + goto out; if (type == PACKET_FANOUT_ROLLOVER || (type_flags & PACKET_FANOUT_FLAG_ROLLOVER)) { - po->rollover = kzalloc(sizeof(*po->rollover), GFP_KERNEL); - if (!po->rollover) - return -ENOMEM; - atomic_long_set(&po->rollover->num, 0); - atomic_long_set(&po->rollover->num_huge, 0); - atomic_long_set(&po->rollover->num_failed, 0); + err = -ENOMEM; + rollover = kzalloc(sizeof(*rollover), GFP_KERNEL); + if (!rollover) + goto out; + atomic_long_set(&rollover->num, 0); + atomic_long_set(&rollover->num_huge, 0); + atomic_long_set(&rollover->num_failed, 0); + po->rollover = rollover; } - mutex_lock(&fanout_mutex); match = NULL; list_for_each_entry(f, &fanout_list, list) { if (f->id == id && @@ -1691,7 +1701,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) match->prot_hook.func = packet_rcv_fanout; match->prot_hook.af_packet_priv = match; match->prot_hook.id_match = match_fanout_group; - dev_add_pack(&match->prot_hook); list_add(&match->list, &fanout_list); } err = -EINVAL; @@ -1708,36 +1717,40 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) } } out: - mutex_unlock(&fanout_mutex); - if (err) { - kfree(po->rollover); + if (err && rollover) { + kfree(rollover); po->rollover = NULL; } + mutex_unlock(&fanout_mutex); return err; } -static void fanout_release(struct sock *sk) +/* If pkt_sk(sk)->fanout->sk_ref is zero, this function removes + * pkt_sk(sk)->fanout from fanout_list and returns pkt_sk(sk)->fanout. + * It is the responsibility of the caller to call fanout_release_data() and + * free the returned packet_fanout (after synchronize_net()) + */ +static struct packet_fanout *fanout_release(struct sock *sk) { struct packet_sock *po = pkt_sk(sk); struct packet_fanout *f; + mutex_lock(&fanout_mutex); f = po->fanout; - if (!f) - return; + if (f) { + po->fanout = NULL; - mutex_lock(&fanout_mutex); - po->fanout = NULL; + if (atomic_dec_and_test(&f->sk_ref)) + list_del(&f->list); + else + f = NULL; - if (atomic_dec_and_test(&f->sk_ref)) { - list_del(&f->list); - dev_remove_pack(&f->prot_hook); - fanout_release_data(f); - kfree(f); + if (po->rollover) + kfree_rcu(po->rollover, rcu); } mutex_unlock(&fanout_mutex); - if (po->rollover) - kfree_rcu(po->rollover, rcu); + return f; } static bool packet_extra_vlan_len_allowed(const struct net_device *dev, @@ -2637,7 +2650,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) int vnet_hdr_len; struct packet_sock *po = pkt_sk(sk); unsigned short gso_type = 0; - int hlen, tlen; + int hlen, tlen, linear; int extra_len = 0; ssize_t n; @@ -2741,8 +2754,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) err = -ENOBUFS; hlen = LL_RESERVED_SPACE(dev); tlen = dev->needed_tailroom; - skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, - __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len), + linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len); + linear = max(linear, min_t(int, len, dev->hard_header_len)); + skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear, msg->msg_flags & MSG_DONTWAIT, &err); if (skb == NULL) goto out_unlock; @@ -2845,6 +2859,7 @@ static int packet_release(struct socket *sock) { struct sock *sk = sock->sk; struct packet_sock *po; + struct packet_fanout *f; struct net *net; union tpacket_req_u req_u; @@ -2884,9 +2899,14 @@ static int packet_release(struct socket *sock) packet_set_ring(sk, &req_u, 1, 1); } - fanout_release(sk); + f = fanout_release(sk); synchronize_net(); + + if (f) { + fanout_release_data(f); + kfree(f); + } /* * Now the socket is dead. No more input will appear. */ @@ -3860,7 +3880,6 @@ static int packet_notifier(struct notifier_block *this, } if (msg == NETDEV_UNREGISTER) { packet_cached_dev_reset(po); - fanout_release(sk); po->ifindex = -1; if (po->prot_hook.dev) dev_put(po->prot_hook.dev); diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c index fb4c60fc2203..fad084d03854 100644 --- a/net/rmnet_data/rmnet_data_config.c +++ b/net/rmnet_data/rmnet_data_config.c @@ -638,6 +638,13 @@ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) rmnet_header->vnd.vnd_name); break; + case RMNET_NETLINK_NEW_VND_WITH_NAME: + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + resp_rmnet->return_code = rmnet_create_vnd_name( + rmnet_header->vnd.id, + rmnet_header->vnd.vnd_name); + break; + case RMNET_NETLINK_FREE_VND: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; /* Please check rmnet_vnd_free_dev documentation regarding @@ -1087,11 +1094,11 @@ int rmnet_create_vnd(int id) struct net_device *dev; ASSERT_RTNL(); LOGL("(%d);", id); - return rmnet_vnd_create_dev(id, &dev, NULL); + return rmnet_vnd_create_dev(id, &dev, NULL, 0); } /** - * rmnet_create_vnd() - Create virtual network device node + * rmnet_create_vnd_prefix() - Create virtual network device node * @id: RmNet virtual device node id * @prefix: String prefix for device name * @@ -1103,7 +1110,24 @@ int rmnet_create_vnd_prefix(int id, const char *prefix) struct net_device *dev; ASSERT_RTNL(); LOGL("(%d, \"%s\");", id, prefix); - return rmnet_vnd_create_dev(id, &dev, prefix); + return rmnet_vnd_create_dev(id, &dev, prefix, 0); +} + +/** + * rmnet_create_vnd_name() - Create virtual network device node + * @id: RmNet virtual device node id + * @prefix: String prefix for device name + * + * Return: + * - result of rmnet_vnd_create_dev() + */ +int rmnet_create_vnd_name(int id, const char *name) +{ + struct net_device *dev; + + ASSERT_RTNL(); + LOGL("(%d, \"%s\");", id, name); + return rmnet_vnd_create_dev(id, &dev, name, 1); } /** diff --git a/net/rmnet_data/rmnet_data_config.h b/net/rmnet_data/rmnet_data_config.h index f19fbb378111..208c3a40c3ae 100644 --- a/net/rmnet_data/rmnet_data_config.h +++ b/net/rmnet_data/rmnet_data_config.h @@ -124,6 +124,7 @@ int rmnet_config_notify_cb(struct notifier_block *nb, unsigned long event, void *data); int rmnet_create_vnd(int id); int rmnet_create_vnd_prefix(int id, const char *name); +int rmnet_create_vnd_name(int id, const char *name); int rmnet_free_vnd(int id); struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c index 2819da9ae3f2..ede1a54661cd 100644 --- a/net/rmnet_data/rmnet_data_vnd.c +++ b/net/rmnet_data/rmnet_data_vnd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -565,7 +565,7 @@ int rmnet_vnd_init(void) * - RMNET_CONFIG_UNKNOWN_ERROR if register_netdevice() fails */ int rmnet_vnd_create_dev(int id, struct net_device **new_device, - const char *prefix) + const char *prefix, int use_name) { struct net_device *dev; char dev_prefix[IFNAMSIZ]; @@ -581,12 +581,15 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, return RMNET_CONFIG_DEVICE_IN_USE; } - if (!prefix) + if (!prefix && !use_name) p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", RMNET_DATA_DEV_NAME_STR); + else if (prefix && use_name) + p = scnprintf(dev_prefix, IFNAMSIZ, "%s", prefix); + else if (prefix && !use_name) + p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", prefix); else - p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", - prefix); + return RMNET_CONFIG_BAD_ARGUMENTS; if (p >= (IFNAMSIZ-1)) { LOGE("Specified prefix longer than IFNAMSIZ"); return RMNET_CONFIG_BAD_ARGUMENTS; @@ -594,7 +597,7 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, dev = alloc_netdev(sizeof(struct rmnet_vnd_private_s), dev_prefix, - NET_NAME_ENUM, + use_name ? NET_NAME_UNKNOWN : NET_NAME_ENUM, rmnet_vnd_setup); if (!dev) { LOGE("Failed to to allocate netdev for id %d", id); diff --git a/net/rmnet_data/rmnet_data_vnd.h b/net/rmnet_data/rmnet_data_vnd.h index 22ffcfc2e08e..7a1af24fa051 100644 --- a/net/rmnet_data/rmnet_data_vnd.h +++ b/net/rmnet_data/rmnet_data_vnd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,7 +27,7 @@ int rmnet_vnd_do_flow_control(struct net_device *dev, struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev); int rmnet_vnd_get_name(int id, char *name, int name_len); int rmnet_vnd_create_dev(int id, struct net_device **new_device, - const char *prefix); + const char *prefix, int use_name); int rmnet_vnd_free_dev(int id); int rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev); int rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b5fd4ab56156..138f2d667212 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6960,7 +6960,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, */ release_sock(sk); current_timeo = schedule_timeout(current_timeo); - BUG_ON(sk != asoc->base.sk); + if (sk != asoc->base.sk) + goto do_error; lock_sock(sk); *timeo_p = current_timeo; diff --git a/net/socket.c b/net/socket.c index bb11725c0e50..11a2967eaebc 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2245,8 +2245,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, return err; err = sock_error(sock->sk); - if (err) + if (err) { + datagrams = err; goto out_put; + } entry = mmsg; compat_entry = (struct compat_mmsghdr __user *)mmsg; diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 7013eb1313a2..449e4a31a3ec 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -268,7 +268,7 @@ country CN: DFS-FCC (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) + (5735 - 5835 @ 80), (33) # 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm # ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf (57240 - 59400 @ 2160), (28) diff --git a/Documentation/mic/mpssd/.gitignore b/samples/mic/mpssd/.gitignore index 8b7c72f07c92..8b7c72f07c92 100644 --- a/Documentation/mic/mpssd/.gitignore +++ b/samples/mic/mpssd/.gitignore diff --git a/samples/mic/mpssd/Makefile b/samples/mic/mpssd/Makefile new file mode 100644 index 000000000000..3e3ef91fed6b --- /dev/null +++ b/samples/mic/mpssd/Makefile @@ -0,0 +1,27 @@ +ifndef CROSS_COMPILE +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq ($(ARCH),x86) + +PROGS := mpssd +CC = $(CROSS_COMPILE)gcc +CFLAGS := -I../../../usr/include -I../../../tools/include + +ifdef DEBUG +CFLAGS += -DDEBUG=$(DEBUG) +endif + +all: $(PROGS) +mpssd: mpssd.c sysfs.c + $(CC) $(CFLAGS) mpssd.c sysfs.c -o mpssd -lpthread + +install: + install mpssd /usr/sbin/mpssd + install micctrl /usr/sbin/micctrl + +clean: + rm -fr $(PROGS) + +endif +endif diff --git a/Documentation/mic/mpssd/micctrl b/samples/mic/mpssd/micctrl index 8f2629b41c5f..8f2629b41c5f 100755..100644 --- a/Documentation/mic/mpssd/micctrl +++ b/samples/mic/mpssd/micctrl diff --git a/Documentation/mic/mpssd/mpss b/samples/mic/mpssd/mpss index 09ea90931649..09ea90931649 100755..100644 --- a/Documentation/mic/mpssd/mpss +++ b/samples/mic/mpssd/mpss diff --git a/Documentation/mic/mpssd/mpssd.c b/samples/mic/mpssd/mpssd.c index c99a75968c01..c99a75968c01 100644 --- a/Documentation/mic/mpssd/mpssd.c +++ b/samples/mic/mpssd/mpssd.c diff --git a/Documentation/mic/mpssd/mpssd.h b/samples/mic/mpssd/mpssd.h index 8bd64944aacc..8bd64944aacc 100644 --- a/Documentation/mic/mpssd/mpssd.h +++ b/samples/mic/mpssd/mpssd.h diff --git a/Documentation/mic/mpssd/sysfs.c b/samples/mic/mpssd/sysfs.c index 8dd326936083..8dd326936083 100644 --- a/Documentation/mic/mpssd/sysfs.c +++ b/samples/mic/mpssd/sysfs.c diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h index 38ee70f3cd5b..1d8de9edd858 100644 --- a/samples/seccomp/bpf-helper.h +++ b/samples/seccomp/bpf-helper.h @@ -138,7 +138,7 @@ union arg64 { #define ARG_32(idx) \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)) -/* Loads hi into A and lo in X */ +/* Loads lo into M[0] and hi into M[1] and A */ #define ARG_64(idx) \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \ BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \ @@ -153,88 +153,107 @@ union arg64 { BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \ jt -/* Checks the lo, then swaps to check the hi. A=lo,X=hi */ +#define JA32(value, jt) \ + BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \ + jt + +#define JGE32(value, jt) \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \ + jt + +#define JGT32(value, jt) \ + BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \ + jt + +#define JLE32(value, jt) \ + BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \ + jt + +#define JLT32(value, jt) \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ + jt + +/* + * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both + * A and M[1]. This invariant is kept by restoring A if necessary. + */ #define JEQ64(lo, hi, jt) \ + /* if (hi != arg.hi) goto NOMATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + /* if (lo != arg.lo) goto NOMATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) #define JNE64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + /* if (hi != arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo != arg.lo) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - -#define JA32(value, jt) \ - BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \ - jt + BPF_STMT(BPF_LD+BPF_MEM, 1) #define JA64(lo, hi, jt) \ + /* if (hi & arg.hi) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo & arg.lo) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) -#define JGE32(value, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \ - jt - -#define JLT32(value, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ - jt - -/* Shortcut checking if hi > arg.hi. */ #define JGE64(lo, hi, jt) \ + /* if (hi > arg.hi) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo >= arg.lo) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ - jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ - -#define JLT64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) -#define JGT32(value, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \ - jt - -#define JLE32(value, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \ - jt - -/* Check hi > args.hi first, then do the GE checking */ #define JGT64(lo, hi, jt) \ + /* if (hi > arg.hi) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo > arg.lo) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) #define JLE64(lo, hi, jt) \ - BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ - BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ + /* if (hi < arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo <= arg.lo) goto MATCH; */ \ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ - BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ + jt, \ + BPF_STMT(BPF_LD+BPF_MEM, 1) + +#define JLT64(lo, hi, jt) \ + /* if (hi < arg.hi) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ + /* if (hi != arg.hi) goto NOMATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ + BPF_STMT(BPF_LD+BPF_MEM, 0), \ + /* if (lo < arg.lo) goto MATCH; */ \ + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \ + BPF_STMT(BPF_LD+BPF_MEM, 1), \ jt, \ - BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ + BPF_STMT(BPF_LD+BPF_MEM, 1) #define LOAD_SYSCALL_NR \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index 2f09d8801a96..facecedc3827 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -64,7 +64,8 @@ uint8_t ice_key[ICE_KEY_SIZE]; uint8_t ice_salt[ICE_KEY_SIZE]; -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) { struct scm_desc desc = {0}; int ret; @@ -84,6 +85,9 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) if (!tzbuf_key || !tzbuf_salt) return -ENOMEM; + if (storage_type == NULL) + return -EINVAL; + memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); @@ -103,7 +107,8 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; - ret = qcom_ice_setup_ice_hw("ufs", true); + ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); + if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; @@ -111,7 +116,7 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) ret = scm_call2(smc_id, &desc); - qcom_ice_setup_ice_hw("ufs", false); + ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); pr_debug(" %s , ret = %d\n", __func__, ret); if (ret) { @@ -127,7 +132,7 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt) } -int qti_pfk_ice_invalidate_key(uint32_t index) +int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) { struct scm_desc desc = {0}; int ret; @@ -137,13 +142,17 @@ int qti_pfk_ice_invalidate_key(uint32_t index) if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) return -EINVAL; + if (storage_type == NULL) + return -EINVAL; + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; pr_debug(" %s , smc_id = 0x%x\n", __func__, smc_id); desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; desc.args[0] = index; - ret = qcom_ice_setup_ice_hw("ufs", true); + ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); + if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; @@ -151,7 +160,7 @@ int qti_pfk_ice_invalidate_key(uint32_t index) ret = scm_call2(smc_id, &desc); - qcom_ice_setup_ice_hw("ufs", false); + ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); pr_debug(" %s , ret = %d\n", __func__, ret); if (ret) diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index fe3f2ad3950c..fb7c0d142953 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,8 +25,9 @@ int pfk_ice_init(void); int pfk_ice_deinit(void); -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt); -int qti_pfk_ice_invalidate_key(uint32_t index); +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type); +int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); #endif /* PFK_ICE_H_ */ diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 39e67569a1dd..3a12dd172d04 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -23,6 +23,7 @@ * Empty entries always have the oldest timestamp. */ +#include <linux/module.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <crypto/ice.h> @@ -51,10 +52,12 @@ /** The maximum key and salt size */ #define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE #define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE +#define PFK_UFS "ufs" static DEFINE_SPINLOCK(kc_lock); static unsigned long flags; static bool kc_ready; +static char *s_type = "sdcc"; /** * enum pfk_kc_entry_state - state of the entry inside kc table @@ -404,7 +407,7 @@ static int kc_update_entry(struct kc_entry *entry, const unsigned char *key, kc_spin_unlock(); ret = qti_pfk_ice_set_key(entry->key_index, entry->key, - entry->salt); + entry->salt, s_type); kc_spin_lock(); return ret; @@ -524,7 +527,8 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, kc_update_timestamp(entry); entry->state = ACTIVE_ICE_LOADED; - if (async) + if (async && (!strcmp(s_type, + (char *)PFK_UFS))) entry->loaded_ref_cnt++; break; @@ -544,7 +548,8 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, * sync calls from within work thread do not pass * requests further to HW */ - if (async) + if (async && (!strcmp(s_type, + (char *)PFK_UFS))) entry->loaded_ref_cnt++; } @@ -556,9 +561,9 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, case (ACTIVE_ICE_LOADED): kc_update_timestamp(entry); - if (async) + if (async && (!strcmp(s_type, + (char *)PFK_UFS))) entry->loaded_ref_cnt++; - break; case(SCM_ERROR): ret = entry->scm_error; @@ -616,24 +621,36 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, return; } - ref_cnt = --entry->loaded_ref_cnt; + if (!strcmp(s_type, (char *)PFK_UFS)) { + ref_cnt = --entry->loaded_ref_cnt; - if (ref_cnt < 0) - pr_err("internal error, ref count should never be negative\n"); + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); - if (!ref_cnt) { + if (!ref_cnt) { + entry->state = INACTIVE; + /* + * wake-up invalidation if it's waiting + * for the entry to be released + */ + if (entry->thread_pending) { + tmp_pending = entry->thread_pending; + entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; + } + } + } else { entry->state = INACTIVE; /* * wake-up invalidation if it's waiting * for the entry to be released - */ + */ if (entry->thread_pending) { - tmp_pending = entry->thread_pending; + wake_up_process(entry->thread_pending); entry->thread_pending = NULL; - - kc_spin_unlock(); - wake_up_process(tmp_pending); - return; } } @@ -689,7 +706,7 @@ int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, kc_spin_unlock(); - qti_pfk_ice_invalidate_key(entry->key_index); + qti_pfk_ice_invalidate_key(entry->key_index, s_type); kc_spin_lock(); kc_entry_finish_invalidating(entry); @@ -771,7 +788,8 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size) temp_indexes_size--; for (i = temp_indexes_size; i >= 0 ; i--) qti_pfk_ice_invalidate_key( - kc_entry_at_index(temp_indexes[i])->key_index); + kc_entry_at_index(temp_indexes[i])->key_index, + s_type); /* fall through */ res = 0; @@ -814,7 +832,8 @@ int pfk_kc_clear(void) kc_spin_unlock(); for (i = 0; i < PFK_KC_TABLE_SIZE; i++) - qti_pfk_ice_invalidate_key(kc_entry_at_index(i)->key_index); + qti_pfk_ice_invalidate_key(kc_entry_at_index(i)->key_index, + s_type); /* fall through */ res = 0; @@ -850,3 +869,36 @@ void pfk_kc_clear_on_reset(void) } kc_spin_unlock(); } + +static int pfk_kc_find_storage_type(char **device) +{ + char boot[20] = {'\0'}; + char *match = (char *)strnstr(saved_command_line, + "androidboot.bootdevice=", + strlen(saved_command_line)); + if (match) { + memcpy(boot, (match + strlen("androidboot.bootdevice=")), + sizeof(boot) - 1); + if (strnstr(boot, PFK_UFS, strlen(boot))) + *device = PFK_UFS; + + return 0; + } + return -EINVAL; +} + +static int __init pfk_kc_pre_init(void) +{ + return pfk_kc_find_storage_type(&s_type); +} + +static void __exit pfk_kc_exit(void) +{ + s_type = NULL; +} + +module_init(pfk_kc_pre_init); +module_exit(pfk_kc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Per-File-Key-KC driver"); diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h index 0b0ec8825c15..dc4ad15b359d 100644 --- a/security/pfe/pfk_kc.h +++ b/security/pfe/pfk_kc.h @@ -27,7 +27,7 @@ int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, int pfk_kc_remove_key(const unsigned char *key, size_t key_size); int pfk_kc_clear(void); void pfk_kc_clear_on_reset(void); - +extern char *saved_command_line; #endif /* PFK_KC_H_ */ diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 1d5acbe0c08b..86240d02b530 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -135,6 +135,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, f->tail = cell; if (f->head == NULL) f->head = cell; + cell->next = NULL; f->cells++; spin_unlock_irqrestore(&f->lock, flags); @@ -214,6 +215,8 @@ void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, spin_lock_irqsave(&f->lock, flags); cell->next = f->head; f->head = cell; + if (!f->tail) + f->tail = cell; f->cells++; spin_unlock_irqrestore(&f->lock, flags); } diff --git a/sound/core/timer.c b/sound/core/timer.c index 05a31df05c00..30b28e80c6e6 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1704,9 +1704,21 @@ static int snd_timer_user_params(struct file *file, return -EBADFD; if (copy_from_user(¶ms, _params, sizeof(params))) return -EFAULT; - if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) { - err = -EINVAL; - goto _end; + if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { + u64 resolution; + + if (params.ticks < 1) { + err = -EINVAL; + goto _end; + } + + /* Don't allow resolution less than 1ms */ + resolution = snd_timer_resolution(tu->timeri); + resolution *= params.ticks; + if (resolution < 1000000) { + err = -EINVAL; + goto _end; + } } if (params.queue_size > 0 && (params.queue_size < 32 || params.queue_size > 1024)) { diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 9667cbfb0ca2..ab4cdab5cfa5 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -27,12 +27,6 @@ #include "cthw20k1.h" #include "ct20k1reg.h" -#if BITS_PER_LONG == 32 -#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ -#else -#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ -#endif - struct hw20k1 { struct hw hw; spinlock_t reg_20k1_lock; @@ -1904,19 +1898,18 @@ static int hw_card_start(struct hw *hw) { int err; struct pci_dev *pci = hw->pci; + const unsigned int dma_bits = BITS_PER_LONG; err = pci_enable_device(pci); if (err < 0) return err; /* Set DMA transfer mask */ - if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 || - dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) { - dev_err(hw->card->dev, - "architecture does not support PCI busmaster DMA with mask 0x%llx\n", - CT_XFI_DMA_MASK); - err = -ENXIO; - goto error1; + if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) { + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits)); + } else { + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } if (!hw->io_base) { diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 9dc2950e1ab7..d86678c2a957 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -26,12 +26,6 @@ #include "cthw20k2.h" #include "ct20k2reg.h" -#if BITS_PER_LONG == 32 -#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ -#else -#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ -#endif - struct hw20k2 { struct hw hw; /* for i2c */ @@ -2029,19 +2023,18 @@ static int hw_card_start(struct hw *hw) int err = 0; struct pci_dev *pci = hw->pci; unsigned int gctl; + const unsigned int dma_bits = BITS_PER_LONG; err = pci_enable_device(pci); if (err < 0) return err; /* Set DMA transfer mask */ - if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 || - dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) { - dev_err(hw->card->dev, - "architecture does not support PCI busmaster DMA with mask 0x%llx\n", - CT_XFI_DMA_MASK); - err = -ENXIO; - goto error1; + if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) { + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits)); + } else { + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } if (!hw->io_base) { diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ad4a1e9a3ae1..8f3e5e9d8bdb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2208,9 +2208,9 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lewisburg */ { PCI_DEVICE(0x8086, 0xa1f0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, { PCI_DEVICE(0x8086, 0xa270), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 00c50d58f108..cf0785ddbd14 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5560,6 +5560,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -5674,6 +5675,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), @@ -6047,6 +6049,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, ALC298_STANDARD_PINS, {0x17, 0x90170150}), + SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME, + {0x12, 0xb7a60140}, + {0x13, 0xb7a60150}, + {0x17, 0x90170110}, + {0x1a, 0x03011020}, + {0x21, 0x03211030}), {} }; diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c index 6de88aff0dd4..cb230f38db22 100644 --- a/sound/soc/codecs/audio-ext-clk-up.c +++ b/sound/soc/codecs/audio-ext-clk-up.c @@ -34,6 +34,7 @@ struct pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *sleep; struct pinctrl_state *active; + char __iomem *base; }; struct audio_ext_ap_clk { @@ -192,8 +193,10 @@ static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw) pr_err("%s afe_set_digital_codec_core_clock failed\n", __func__); return ret; - } + } + if (pnctrl_info->base) + iowrite32(1, pnctrl_info->base); return 0; } @@ -219,6 +222,8 @@ static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw) if (ret < 0) pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n", __func__, ret); + if (pnctrl_info->base) + iowrite32(0, pnctrl_info->base); } static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw) @@ -381,9 +386,11 @@ static struct clk_hw *audio_msm_hws1[] = { static int audio_get_pinctrl(struct platform_device *pdev, enum audio_clk_mux mux) { + struct device *dev = &pdev->dev; struct pinctrl_info *pnctrl_info; struct pinctrl *pinctrl; int ret; + u32 reg; switch (mux) { case AP_CLK2: @@ -396,21 +403,20 @@ static int audio_get_pinctrl(struct platform_device *pdev, pnctrl_info = &audio_lpass_mclk2.pnctrl_info; break; default: - dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n", + dev_err(dev, "%s Not a valid MUX ID: %d\n", __func__, mux); return -EINVAL; } - pnctrl_info = &audio_ap_clk2.pnctrl_info; if (pnctrl_info->pinctrl) { - dev_dbg(&pdev->dev, "%s: already requested before\n", + dev_dbg(dev, "%s: already requested before\n", __func__); return -EINVAL; } - pinctrl = devm_pinctrl_get(&pdev->dev); + pinctrl = devm_pinctrl_get(dev); if (IS_ERR_OR_NULL(pinctrl)) { - dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n", + dev_dbg(dev, "%s: Unable to get pinctrl handle\n", __func__); return -EINVAL; } @@ -418,13 +424,13 @@ static int audio_get_pinctrl(struct platform_device *pdev, /* get all state handles from Device Tree */ pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep"); if (IS_ERR(pnctrl_info->sleep)) { - dev_err(&pdev->dev, "%s: could not get sleep pinstate\n", + dev_err(dev, "%s: could not get sleep pinstate\n", __func__); goto err; } pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active"); if (IS_ERR(pnctrl_info->active)) { - dev_err(&pdev->dev, "%s: could not get active pinstate\n", + dev_err(dev, "%s: could not get active pinstate\n", __func__); goto err; } @@ -432,10 +438,22 @@ static int audio_get_pinctrl(struct platform_device *pdev, ret = pinctrl_select_state(pnctrl_info->pinctrl, pnctrl_info->sleep); if (ret) { - dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n", + dev_err(dev, "%s: Disable TLMM pins failed with %d\n", __func__, ret); goto err; } + + ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", ®); + if (ret < 0) { + dev_dbg(dev, "miss mclk reg\n"); + } else { + pnctrl_info->base = ioremap(reg, sizeof(u32)); + if (pnctrl_info->base == NULL) { + dev_err(dev, "%s ioremap failed\n", __func__); + goto err; + } + } + return 0; err: diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c index 1d1dd0f61f28..db723e5ec1f4 100644 --- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c +++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c @@ -854,8 +854,8 @@ static int msm_sdw_config_compander(struct snd_soc_codec *codec, int comp, if (!msm_sdw->comp_enabled[comp]) return 0; - comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 8); - rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 20); + comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 0x20); + rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 0x1E0); if (SND_SOC_DAPM_EVENT_ON(event)) { /* Enable Compander Clock */ @@ -1044,7 +1044,7 @@ static int msm_sdw_swrm_read(void *handle, int reg) * Add sleep as SWR slave access read takes time. * Allow for RD_DONE to complete for previous register if any. */ - usleep_range(50, 55); + usleep_range(100, 105); /* read_lock */ mutex_lock(&msm_sdw->sdw_read_lock); @@ -1079,6 +1079,11 @@ static int msm_sdw_bulk_write(struct msm_sdw_priv *msm_sdw, sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0; sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0; + /* + * Add sleep as SWR slave write takes time. + * Allow for any previous pending write to complete. + */ + usleep_range(50, 55); for (i = 0; i < len; i += 2) { /* First Write the Data to register */ ret = regmap_bulk_write(msm_sdw->regmap, @@ -1656,12 +1661,15 @@ static int msm_sdw_notifier_service_cb(struct notifier_block *nb, service_nb); bool adsp_ready = false; unsigned long timeout; + static bool initial_boot = true; pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode); mutex_lock(&msm_sdw->codec_mutex); switch (opcode) { case AUDIO_NOTIFIER_SERVICE_DOWN: + if (initial_boot) + break; msm_sdw->int_mclk1_enabled = false; msm_sdw->dev_up = false; for (i = 0; i < msm_sdw->nr; i++) @@ -1669,6 +1677,8 @@ static int msm_sdw_notifier_service_cb(struct notifier_block *nb, SWR_DEVICE_DOWN, NULL); break; case AUDIO_NOTIFIER_SERVICE_UP: + if (initial_boot) + initial_boot = false; if (!q6core_is_adsp_ready()) { dev_dbg(msm_sdw->dev, "ADSP isn't ready\n"); timeout = jiffies + diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index 04440262fe7a..52dae06a7ee8 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -1436,11 +1436,11 @@ static int msm_anlg_cdc_codec_enable_clock_block(struct snd_soc_codec *codec, if (enable) { snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30); + msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON); snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80); snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C); - msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON); } else { snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00); @@ -3760,8 +3760,8 @@ static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec) snd_soc_write(codec, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93); - atomic_set(&pdata->int_mclk0_enabled, false); msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN); + atomic_set(&pdata->int_mclk0_enabled, false); set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask); snd_soc_card_change_online_state(codec->component.card, 0); @@ -3797,6 +3797,9 @@ static int msm_anlg_cdc_device_up(struct snd_soc_codec *codec) msm_anlg_cdc_configure_cap(codec, false, false); wcd_mbhc_stop(&sdm660_cdc_priv->mbhc); wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc); + /* Disable mechanical detection and set type to insertion */ + snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, + 0xA0, 0x20); ret = wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb, &intr_ids, wcd_mbhc_registers, true); if (ret) @@ -3819,17 +3822,22 @@ static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb, bool adsp_ready = false; bool timedout; unsigned long timeout; + static bool initial_boot = true; codec = sdm660_cdc_priv->codec; dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode); switch (opcode) { case AUDIO_NOTIFIER_SERVICE_DOWN: + if (initial_boot) + break; dev_dbg(codec->dev, "ADSP is about to power down. teardown/reset codec\n"); msm_anlg_cdc_device_down(codec); break; case AUDIO_NOTIFIER_SERVICE_UP: + if (initial_boot) + initial_boot = false; dev_dbg(codec->dev, "ADSP is about to power up. bring up codec\n"); diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index 1b56ef4d5fbe..3aa502ba065f 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -1028,7 +1028,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, break; case DIG_CDC_EVENT_PRE_RX1_INT_ON: snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14); + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x28); snd_soc_update_bits(codec, MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10); snd_soc_update_bits(codec, @@ -1036,7 +1036,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, break; case DIG_CDC_EVENT_PRE_RX2_INT_ON: snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14); + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x28); snd_soc_update_bits(codec, MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10); snd_soc_update_bits(codec, @@ -1044,7 +1044,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, break; case DIG_CDC_EVENT_POST_RX1_INT_OFF: snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00); + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x00); snd_soc_update_bits(codec, MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF); snd_soc_update_bits(codec, @@ -1052,7 +1052,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block, break; case DIG_CDC_EVENT_POST_RX2_INT_OFF: snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00); + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x00); snd_soc_update_bits(codec, MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF); snd_soc_update_bits(codec, diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index e6e40d1d6a8f..4b98d1ee0ecd 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -2953,6 +2953,7 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_right_ocp, mbhc); if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier) mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false); + wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); mutex_destroy(&mbhc->codec_resource_lock); mutex_destroy(&mbhc->hphl_pa_lock); mutex_destroy(&mbhc->hphr_pa_lock); diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c index b03a8a9caed7..3d2fe2c6bed9 100644 --- a/sound/soc/codecs/wcd-spi.c +++ b/sound/soc/codecs/wcd-spi.c @@ -81,8 +81,15 @@ #define WCD_SPI_WORD_BYTE_CNT (4) #define WCD_SPI_RW_MULTI_MIN_LEN (16) -/* Max size is closest multiple of 16 less than 64Kbytes */ -#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 16) +/* Max size is 32 bytes less than 64Kbytes */ +#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 32) + +/* + * Max size for the pre-allocated buffers is the max + * possible read/write length + 32 bytes for the SPI + * read/write command header itself. + */ +#define WCD_SPI_RW_MAX_BUF_SIZE (WCD_SPI_RW_MULTI_MAX_LEN + 32) /* Alignment requirements */ #define WCD_SPI_RW_MIN_ALIGN WCD_SPI_WORD_BYTE_CNT @@ -148,6 +155,10 @@ struct wcd_spi_priv { /* Completion object to indicate system resume completion */ struct completion resume_comp; + + /* Buffers to hold memory used for transfers */ + void *tx_buf; + void *rx_buf; }; enum xfer_request { @@ -229,17 +240,18 @@ static int wcd_spi_read_single(struct spi_device *spi, struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0]; struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1]; - u8 *tx_buf; + u8 *tx_buf = wcd_spi->tx_buf; u32 frame = 0; int ret; dev_dbg(&spi->dev, "%s: remote_addr = 0x%x\n", __func__, remote_addr); - tx_buf = kzalloc(WCD_SPI_READ_SINGLE_LEN, - GFP_KERNEL | GFP_DMA); - if (!tx_buf) + if (!tx_buf) { + dev_err(&spi->dev, "%s: tx_buf not allocated\n", + __func__); return -ENOMEM; + } frame |= WCD_SPI_READ_FRAME_OPCODE; frame |= remote_addr & WCD_CMD_ADDR_MASK; @@ -255,7 +267,6 @@ static int wcd_spi_read_single(struct spi_device *spi, rx_xfer->len = sizeof(*val); ret = spi_sync(spi, &wcd_spi->msg2); - kfree(tx_buf); return ret; } @@ -266,8 +277,8 @@ static int wcd_spi_read_multi(struct spi_device *spi, { struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); struct spi_transfer *xfer = &wcd_spi->xfer1; - u8 *tx_buf; - u8 *rx_buf; + u8 *tx_buf = wcd_spi->tx_buf; + u8 *rx_buf = wcd_spi->rx_buf; u32 frame = 0; int ret; @@ -277,15 +288,9 @@ static int wcd_spi_read_multi(struct spi_device *spi, frame |= WCD_SPI_FREAD_FRAME_OPCODE; frame |= remote_addr & WCD_CMD_ADDR_MASK; - tx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len, - GFP_KERNEL | GFP_DMA); - if (!tx_buf) - return -ENOMEM; - - rx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len, - GFP_KERNEL | GFP_DMA); - if (!rx_buf) { - kfree(tx_buf); + if (!tx_buf || !rx_buf) { + dev_err(&spi->dev, "%s: %s not allocated\n", __func__, + (!tx_buf) ? "tx_buf" : "rx_buf"); return -ENOMEM; } @@ -305,8 +310,6 @@ static int wcd_spi_read_multi(struct spi_device *spi, memcpy(data, rx_buf + WCD_SPI_CMD_FREAD_LEN, len); done: - kfree(tx_buf); - kfree(rx_buf); return ret; } @@ -343,7 +346,7 @@ static int wcd_spi_write_multi(struct spi_device *spi, struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); struct spi_transfer *xfer = &wcd_spi->xfer1; u32 frame = 0; - u8 *tx_buf; + u8 *tx_buf = wcd_spi->tx_buf; int xfer_len, ret; dev_dbg(&spi->dev, "%s: addr = 0x%x len = %zd\n", @@ -355,9 +358,11 @@ static int wcd_spi_write_multi(struct spi_device *spi, frame = cpu_to_be32(frame); xfer_len = len + sizeof(frame); - tx_buf = kzalloc(xfer_len, GFP_KERNEL); - if (!tx_buf) + if (!tx_buf) { + dev_err(&spi->dev, "%s: tx_buf not allocated\n", + __func__); return -ENOMEM; + } memcpy(tx_buf, &frame, sizeof(frame)); memcpy(tx_buf + sizeof(frame), data, len); @@ -371,8 +376,6 @@ static int wcd_spi_write_multi(struct spi_device *spi, dev_err(&spi->dev, "%s: Failed, addr = 0x%x, len = %zd\n", __func__, remote_addr, len); - kfree(tx_buf); - return ret; } @@ -1330,6 +1333,23 @@ static int wcd_spi_component_bind(struct device *dev, spi_message_init(&wcd_spi->msg2); spi_message_add_tail(&wcd_spi->xfer2[0], &wcd_spi->msg2); spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2); + + /* Pre-allocate the buffers */ + wcd_spi->tx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE, + GFP_KERNEL | GFP_DMA); + if (!wcd_spi->tx_buf) { + ret = -ENOMEM; + goto done; + } + + wcd_spi->rx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE, + GFP_KERNEL | GFP_DMA); + if (!wcd_spi->rx_buf) { + kfree(wcd_spi->tx_buf); + wcd_spi->tx_buf = NULL; + ret = -ENOMEM; + goto done; + } done: return ret; } @@ -1347,6 +1367,11 @@ static void wcd_spi_component_unbind(struct device *dev, spi_transfer_del(&wcd_spi->xfer1); spi_transfer_del(&wcd_spi->xfer2[0]); spi_transfer_del(&wcd_spi->xfer2[1]); + + kfree(wcd_spi->tx_buf); + kfree(wcd_spi->rx_buf); + wcd_spi->tx_buf = NULL; + wcd_spi->rx_buf = NULL; } static const struct component_ops wcd_spi_component_ops = { diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 676c3b0335ef..eaaca97e2b8e 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -104,6 +104,7 @@ struct wsa881x_priv { int state; struct delayed_work ocp_ctl_work; struct device_node *wsa_rst_np; + int pa_mute; }; #define SWR_SLV_MAX_REG_ADDR 0x390 @@ -171,9 +172,41 @@ static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol, return 0; } -static const struct snd_kcontrol_new wsa_analog_gain_controls[] = { +static int wsa881x_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wsa881x->pa_mute; + + return 0; +} + +static int wsa881x_set_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec); + int value = ucontrol->value.integer.value[0]; + + dev_dbg(codec->dev, "%s: mute current %d, new %d\n", + __func__, wsa881x->pa_mute, value); + + if (value) + snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00); + wsa881x->pa_mute = value; + + return 0; +} + + +static const struct snd_kcontrol_new wsa_snd_controls[] = { SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum, wsa_pa_gain_get, wsa_pa_gain_put), + SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0, + wsa881x_get_mute, wsa881x_set_mute), }; static int codec_debug_open(struct inode *inode, struct file *file) @@ -1050,8 +1083,8 @@ static int wsa881x_probe(struct snd_soc_codec *codec) wsa881x->tz_pdata.codec = codec; wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read; wsa881x_init_thermal(&wsa881x->tz_pdata); - snd_soc_add_codec_controls(codec, wsa_analog_gain_controls, - ARRAY_SIZE(wsa_analog_gain_controls)); + snd_soc_add_codec_controls(codec, wsa_snd_controls, + ARRAY_SIZE(wsa_snd_controls)); INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work); return 0; } diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 041a91e28988..ec02cdf3ca3c 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -496,6 +496,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text); static struct platform_device *spdev; @@ -2263,6 +2265,54 @@ static int mi2s_get_sample_rate(int value) return sample_rate; } +static int mi2s_get_format(int value) +{ + int format; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 3: + format = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int mi2s_get_format_value(int format) +{ + int value; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + value = 2; + break; + case SNDRV_PCM_FORMAT_S32_LE: + value = 3; + break; + default: + value = 0; + break; + } + return value; +} + static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2395,6 +2445,78 @@ static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, return 1; } +static int msm_mi2s_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_get_format_value(mi2s_rx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].bit_format = + mi2s_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_get_format_value(mi2s_tx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].bit_format = + mi2s_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + static int msm_hifi_ctrl(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); @@ -2647,6 +2769,22 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs, msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("PRIM_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("PRIM_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("SEC_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("SEC_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("TERT_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("TERT_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("QUAT_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("QUAT_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get, msm_hifi_put), }; @@ -3111,48 +3249,64 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, break; case MSM_BACKEND_DAI_PRI_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[PRIM_MI2S].bit_format); rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate; channels->min = channels->max = mi2s_rx_cfg[PRIM_MI2S].channels; break; case MSM_BACKEND_DAI_PRI_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[PRIM_MI2S].bit_format); rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate; channels->min = channels->max = mi2s_tx_cfg[PRIM_MI2S].channels; break; case MSM_BACKEND_DAI_SECONDARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[SEC_MI2S].bit_format); rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate; channels->min = channels->max = mi2s_rx_cfg[SEC_MI2S].channels; break; case MSM_BACKEND_DAI_SECONDARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[SEC_MI2S].bit_format); rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate; channels->min = channels->max = mi2s_tx_cfg[SEC_MI2S].channels; break; case MSM_BACKEND_DAI_TERTIARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[TERT_MI2S].bit_format); rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate; channels->min = channels->max = mi2s_rx_cfg[TERT_MI2S].channels; break; case MSM_BACKEND_DAI_TERTIARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[TERT_MI2S].bit_format); rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate; channels->min = channels->max = mi2s_tx_cfg[TERT_MI2S].channels; break; case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[QUAT_MI2S].bit_format); rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate; channels->min = channels->max = mi2s_rx_cfg[QUAT_MI2S].channels; break; case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[QUAT_MI2S].bit_format); rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate; channels->min = channels->max = mi2s_tx_cfg[QUAT_MI2S].channels; @@ -3972,6 +4126,7 @@ static u32 get_mi2s_bits_per_sample(u32 bit_format) u32 bit_per_sample; switch (bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S24_3LE: case SNDRV_PCM_FORMAT_S24_LE: bit_per_sample = 32; @@ -5239,7 +5394,6 @@ static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = { .platform_name = "msm-pcm-hostless", .dynamic = 1, .dpcm_playback = 1, - .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 8e986a74ffff..2929ea0d735b 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -45,6 +45,7 @@ #include <sound/msm-dts-eagle.h> #include "msm-pcm-routing-v2.h" +#include "msm-qti-pp-config.h" #define DSP_PP_BUFFERING_IN_MSEC 25 #define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150 @@ -543,12 +544,19 @@ static void compr_event_handler(uint32_t opcode, unsigned long flags; uint64_t read_size; uint32_t *buff_addr; + struct snd_soc_pcm_runtime *rtd; + int ret = 0; if (!prtd) { pr_err("%s: prtd is NULL\n", __func__); return; } cstream = prtd->cstream; + if (!cstream) { + pr_err("%s: cstream is NULL\n", __func__); + return; + } + ac = prtd->audio_client; /* @@ -716,6 +724,23 @@ static void compr_event_handler(uint32_t opcode, prtd->gapless_state.gapless_transition = 0; spin_unlock_irqrestore(&prtd->lock, flags); break; + case ASM_STREAM_PP_EVENT: + pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__); + rtd = cstream->private_data; + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + return; + } + + ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, + payload); + if (ret) { + pr_err("%s: failed to inform mixer ctrl. err = %d\n", + __func__, ret); + return; + } + + break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: { pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n"); @@ -815,6 +840,10 @@ static void compr_event_handler(uint32_t opcode, } atomic_set(&prtd->close, 0); break; + case ASM_STREAM_CMD_REGISTER_PP_EVENTS: + pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:", + __func__); + break; default: break; } @@ -3578,6 +3607,65 @@ end: return rc; } +static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_compr_audio *prtd; + int ret = 0, param_length = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(¶m_length, ucontrol->value.bytes.data, + sizeof(param_length)); + if ((param_length + sizeof(param_length)) + >= sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, param_length); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_stream_cmd(prtd->audio_client, + ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ucontrol->value.bytes.data + sizeof(param_length), + param_length); + if (ret < 0) + pr_err("%s: failed to register pp event. err = %d\n", + __func__, ret); +done: + return ret; +} + static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3854,6 +3942,117 @@ static int msm_compr_add_query_audio_effect_control( return 0; } +static int msm_compr_add_audio_adsp_stream_cmd_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CMD; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_compr_adsp_stream_cmd_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str; + fe_audio_adsp_stream_cmd_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_stream_cmd_config_control, + ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_compr_add_audio_adsp_stream_callback_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol *kctl; + + struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_callback_info, + .get = msm_adsp_stream_callback_get, + .put = msm_adsp_stream_callback_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_callback_config_control[0].name = mixer_str; + fe_audio_adsp_callback_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_callback_config_control, + ARRAY_SIZE(fe_audio_adsp_callback_config_control)); + if (ret < 0) { + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl->private_data = NULL; +free_mixer_str: + kfree(mixer_str); +done: + return ret; +} + static int msm_compr_add_dec_runtime_params_control( struct snd_soc_pcm_runtime *rtd) { @@ -4048,6 +4247,16 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add Compr Audio Effects Control\n", __func__); + rc = msm_compr_add_audio_adsp_stream_cmd_control(rtd); + if (rc) + pr_err("%s: Could not add Compr ADSP Stream Cmd Control\n", + __func__); + + rc = msm_compr_add_audio_adsp_stream_callback_control(rtd); + if (rc) + pr_err("%s: Could not add Compr ADSP Stream Callback Control\n", + __func__); + rc = msm_compr_add_query_audio_effect_control(rtd); if (rc) pr_err("%s: Could not add Compr Query Audio Effect Control\n", diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 7928c3791f96..73eadfa4eebb 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -37,6 +37,7 @@ #include "msm-pcm-q6-v2.h" #include "msm-pcm-routing-v2.h" +#include "msm-qti-pp-config.h" enum stream_state { IDLE = 0, @@ -147,6 +148,8 @@ static void event_handler(uint32_t opcode, uint32_t idx = 0; uint32_t size = 0; uint8_t buf_index; + struct snd_soc_pcm_runtime *rtd; + int ret = 0; switch (opcode) { case ASM_DATA_EVENT_WRITE_DONE_V2: { @@ -223,6 +226,29 @@ static void event_handler(uint32_t opcode, } break; } + case ASM_STREAM_PP_EVENT: { + pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__); + if (!substream) { + pr_err("%s: substream is NULL.\n", __func__); + return; + } + + rtd = substream->private_data; + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + return; + } + + ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, + payload); + if (ret) { + pr_err("%s: failed to inform mixer ctl. err = %d\n", + __func__, ret); + return; + } + + break; + } case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case ASM_SESSION_CMD_RUN_V2: @@ -252,6 +278,10 @@ static void event_handler(uint32_t opcode, } atomic_set(&prtd->start, 1); break; + case ASM_STREAM_CMD_REGISTER_PP_EVENTS: + pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:", + __func__); + break; default: pr_debug("%s:Payload = [0x%x]stat[0x%x]\n", __func__, payload[0], payload[1]); @@ -1036,6 +1066,177 @@ static struct snd_pcm_ops msm_pcm_ops = { .mmap = msm_pcm_mmap, }; +static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm); + struct msm_plat_data *pdata = dev_get_drvdata(platform->dev); + struct snd_pcm_substream *substream; + struct msm_audio *prtd; + int ret = 0, param_length = 0; + + if (!pdata) { + pr_err("%s pdata is NULL\n", __func__); + ret = -ENODEV; + goto done; + } + + substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (!substream) { + pr_err("%s substream not found\n", __func__); + ret = -EINVAL; + goto done; + } + + if (!substream->runtime) { + pr_err("%s substream runtime not found\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = substream->runtime->private_data; + if (prtd->audio_client == NULL) { + pr_err("%s prtd is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(¶m_length, ucontrol->value.bytes.data, + sizeof(param_length)); + if ((param_length + sizeof(param_length)) + >= sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, param_length); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_stream_cmd(prtd->audio_client, + ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ucontrol->value.bytes.data + sizeof(param_length), + param_length); + if (ret < 0) + pr_err("%s: failed to register pp event. err = %d\n", + __func__, ret); +done: + return ret; +} + +static int msm_pcm_add_audio_adsp_stream_cmd_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CMD; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_pcm_adsp_stream_cmd_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str; + fe_audio_adsp_stream_cmd_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("Registering new mixer ctl %s\n", mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_stream_cmd_config_control, + ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control)); + if (ret < 0) + pr_err("%s: failed add ctl %s. err = %d\n", + __func__, mixer_str, ret); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_pcm_add_audio_adsp_stream_callback_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol *kctl; + + struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_callback_info, + .get = msm_adsp_stream_callback_get, + .put = msm_adsp_stream_callback_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n", + __func__, rtd->dai_link->name, rtd->dai_link->be_id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_callback_config_control[0].name = mixer_str; + fe_audio_adsp_callback_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_callback_config_control, + ARRAY_SIZE(fe_audio_adsp_callback_config_control)); + if (ret < 0) { + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl->private_data = NULL; +free_mixer_str: + kfree(mixer_str); +done: + return ret; +} + static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume) { int rc = 0; @@ -1549,6 +1750,16 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm Compress Control %d\n", __func__, ret); + ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd); + if (ret) + pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n", + __func__); + + ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd); + if (ret) + pr_err("%s: Could not add pcm ADSP Stream Callback Control\n", + __func__); + return ret; } diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index 6f463c079f19..d4e78604f868 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -817,6 +817,136 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol, return 0; } + +int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + const char *mixer_ctl_name, + uint32_t *payload) +{ + /* adsp pp event notifier */ + struct snd_kcontrol *kctl; + struct snd_ctl_elem_value control; + uint32_t payload_size = 0; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + + if (!rtd || !payload) { + pr_err("%s: %s is NULL\n", __func__, + (!rtd) ? "rtd" : "payload"); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_ATOMIC); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, + rtd->pcm->device); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + control.id = kctl->id; + payload_size = payload[0]; + /* Copy complete payload */ + memcpy(control.value.bytes.data, (void *)payload, + sizeof(payload_size) + payload_size); + kctl->put(kctl, &control); + if (rtd->card->snd_card == NULL) { + pr_err("%s: snd_card is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + snd_ctl_notify(rtd->card->snd_card, + SNDRV_CTL_EVENT_MASK_INFO, + &control.id); +done: + return ret; +} + +int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 512; + + return 0; +} + +int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t payload_size = 0, last_payload_size = 0; + + /* fetch payload size in first four bytes */ + memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t)); + + if (kcontrol->private_data == NULL) { + /* buffer is empty */ + kcontrol->private_data = + kzalloc(payload_size + sizeof(payload_size), + GFP_ATOMIC); + if (kcontrol->private_data == NULL) + return -ENOMEM; + } else { + memcpy(&last_payload_size, kcontrol->private_data, + sizeof(uint32_t)); + if (last_payload_size < payload_size) { + /* new payload size exceeds old one. + * reallocate buffer + */ + kfree(kcontrol->private_data); + kcontrol->private_data = + kzalloc(payload_size + sizeof(payload_size), + GFP_ATOMIC); + if (kcontrol->private_data == NULL) + return -ENOMEM; + } + } + + memcpy(kcontrol->private_data, ucontrol->value.bytes.data, + sizeof(uint32_t) + payload_size); + + return 0; +} + +int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t payload_size = 0; + + if (kcontrol->private_data == NULL) { + pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__); + return -EINVAL; + } + + memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t)); + memcpy(ucontrol->value.bytes.data, kcontrol->private_data, + sizeof(uint32_t) + payload_size); + kfree(kcontrol->private_data); + kcontrol->private_data = NULL; + + return 0; +} + +int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 512; + + return 0; +} + static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h index f8a1da5e7702..70ce20fbd8f8 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. @@ -13,7 +13,17 @@ #define _MSM_QTI_PP_H_ #include <sound/soc.h> - +int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + const char *mixer_ctl_name, + uint32_t *payload); +int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); #ifdef CONFIG_QTI_PP void msm_qti_pp_send_eq_values(int fedai_id); int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 79f27852391f..1ca99c3f9115 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1094,6 +1094,65 @@ fail: return NULL; } +int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, + void *param, uint32_t params_length) +{ + char *asm_params = NULL; + struct apr_hdr hdr; + int sz, rc; + + if (!param || !ac) { + pr_err("%s: %s is NULL\n", __func__, + (!param) ? "param" : "ac"); + rc = -EINVAL; + goto done; + } + + sz = sizeof(struct apr_hdr) + params_length; + asm_params = kzalloc(sz, GFP_KERNEL); + if (!asm_params) { + rc = -ENOMEM; + goto done; + } + + q6asm_add_hdr_async(ac, &hdr, sizeof(struct apr_hdr) + + params_length, TRUE); + atomic_set(&ac->cmd_state_pp, -1); + hdr.opcode = opcode; + memcpy(asm_params, &hdr, sizeof(struct apr_hdr)); + memcpy(asm_params + sizeof(struct apr_hdr), + param, params_length); + rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); + if (rc < 0) { + pr_err("%s: audio adsp pp register failed\n", __func__); + rc = -EINVAL; + goto fail_send_param; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ); + if (!rc) { + pr_err("%s: timeout, adsp pp register\n", __func__); + rc = -ETIMEDOUT; + goto fail_send_param; + } + + if (atomic_read(&ac->cmd_state_pp) > 0) { + pr_err("%s: DSP returned error[%s] adsp pp register\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state_pp))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state_pp)); + goto fail_send_param; + } + + rc = 0; +fail_send_param: + kfree(asm_params); +done: + return rc; +} + struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) { struct audio_client *ac; @@ -1615,6 +1674,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) int32_t ret = 0; union asm_token_struct asm_token; uint8_t buf_index; + char *pp_event_package = NULL; + uint32_t payload_size = 0; if (ac == NULL) { pr_err("%s: ac NULL\n", __func__); @@ -1797,6 +1858,17 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->payload_size); } break; + case ASM_STREAM_CMD_REGISTER_PP_EVENTS: + pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n", + __func__, ac->session, + data->opcode, data->token, + data->src_port, data->dest_port); + if (payload[1] != 0) + pr_err("%s: ASM get param error = %d, resuming\n", + __func__, payload[1]); + atomic_set(&ac->cmd_state_pp, payload[1]); + wake_up(&ac->cmd_wait); + break; default: pr_debug("%s: command[0x%x] not expecting rsp\n", __func__, payload[0]); @@ -1967,6 +2039,26 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2: q6asm_process_mtmx_get_param_rsp(ac, (void *) payload); break; + case ASM_STREAM_PP_EVENT: + pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]", + __func__, payload[0], payload[1]); + /* repack payload for asm_stream_pp_event + * package is composed of size + actual payload + */ + payload_size = data->payload_size; + pp_event_package = + kzalloc(payload_size + sizeof(payload_size), + GFP_ATOMIC); + if (!pp_event_package) + return -ENOMEM; + memcpy((void *)pp_event_package, + &payload_size, sizeof(payload_size)); + memcpy((void *)pp_event_package + sizeof(payload_size), + data->payload, payload_size); + ac->cb(data->opcode, data->token, + (void *)pp_event_package, ac->priv); + kfree(pp_event_package); + return 0; case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2: pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n", __func__, ac->session, payload[0], payload[2], diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c index f64074d442dc..1c03d8c9e797 100644 --- a/sound/soc/msm/sdm660-ext-dai-links.c +++ b/sound/soc/msm/sdm660-ext-dai-links.c @@ -335,7 +335,6 @@ static struct snd_soc_dai_link msm_ext_tasha_fe_dai[] = { .platform_name = "msm-pcm-hostless", .dynamic = 1, .dpcm_playback = 1, - .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c index 191db6c2fa9d..47c988618398 100644 --- a/sound/soc/msm/sdm660-external.c +++ b/sound/soc/msm/sdm660-external.c @@ -1609,6 +1609,9 @@ int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR"); snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1"); snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2"); + } else { + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT1"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT2"); } snd_soc_dapm_sync(dapm); diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index d08e214ec6e7..223d88e25e05 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -2629,7 +2629,7 @@ sub do_run_test { } waitpid $child_pid, 0; - $child_exit = $?; + $child_exit = $? >> 8; my $end_time = time; $test_time = $end_time - $start_time; |
