diff options
269 files changed, 3584 insertions, 1181 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index c264f9f65265..e4622558af55 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -86,9 +86,6 @@ SoCs: - MSM8998 compatible = "qcom,msm8998" -- MSM8998_9x55 - compatible = "qcom,msm8998-9x55" - - MSMHAMSTER compatible = "qcom,msmhamster" @@ -283,8 +280,6 @@ compatible = "qcom,msm8998-rumi" compatible = "qcom,msm8998-cdp" compatible = "qcom,msm8998-mtp" compatible = "qcom,msm8998-qrd" -compatible = "qcom,msm8998-9x55-cdp" -compatible = "qcom,msm8998-9x55-mtp" compatible = "qcom,msmhamster-rumi" compatible = "qcom,msmhamster-cdp" compatible = "qcom,msmhamster-mtp" diff --git a/Documentation/devicetree/bindings/net/can/k61-can.txt b/Documentation/devicetree/bindings/net/can/k61-can.txt new file mode 100644 index 000000000000..ea4a7b4ae035 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/k61-can.txt @@ -0,0 +1,34 @@ +* Kinetis K61 CAN * + +This driver implements SPI slave protocol for Freescale K61 CAN controller. + +Required properties: + - compatible: Should be "fsl,k61" or "nxp,mpc5746c". + - reg: Should contain SPI chip select. + - interrupt-parent: Should specify interrupt controller for the interrupt. + - interrupts: Should contain IRQ line for the CAN controller. + +Optional properties: + - reset-gpio: Reference to the GPIO connected to the reset input. + - pinctrl-names : Names corresponding to the numbered pinctrl states. + - pinctrl-0 : This explains the active state of the GPIO line. + - pinctrl-1 : This explains the suspend state of the GPIO line. + - bits-per-word: Indicate how many bits are in a SPI frame. e.g.: 8, 16, 32. + Default to 16. + - reset-delay-msec: Delay in milliseconds to be applied after resetting the chip. + Default to 1 ms. + +Example: + + can-controller@0 { + compatible = "fsl,k61"; + reg = <0>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <25 0>; + reset-gpio = <&tlmm_pinmux 11 0x1>; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&can_rst_on>; + pinctrl-1 = <&can_rst_off>; + bits-per-word = <8>; + reset-delay-msec = <100>; + }; @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 80 +SUBLEVEL = 82 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg index d1e3b0891a4e..419dca62542a 100644 --- a/android/configs/android-base.cfg +++ b/android/configs/android-base.cfg @@ -139,11 +139,6 @@ CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PREEMPT=y CONFIG_PROFILING=y -CONFIG_QFMT_V2=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QUOTA_TREE=y -CONFIG_QUOTACTL=y CONFIG_RANDOMIZE_BASE=y CONFIG_RTC_CLASS=y CONFIG_RT_GROUP_SCHED=y diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg index 11df0892301b..6550d0423f50 100644 --- a/android/configs/android-recommended.cfg +++ b/android/configs/android-recommended.cfg @@ -110,6 +110,11 @@ CONFIG_POWER_SUPPLY=y CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_RAM=y +CONFIG_QFMT_V2=y +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QUOTA_TREE=y CONFIG_SCHEDSTATS=y CONFIG_SMARTJOYPLUS_FF=y CONFIG_SND=y diff --git a/arch/Kconfig b/arch/Kconfig index 98f64ad1caf1..ed2539c590bf 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -225,8 +225,8 @@ config ARCH_INIT_TASK config ARCH_TASK_STRUCT_ALLOCATOR bool -# Select if arch has its private alloc_thread_info() function -config ARCH_THREAD_INFO_ALLOCATOR +# Select if arch has its private alloc_thread_stack() function +config ARCH_THREAD_STACK_ALLOCATOR bool # Select if arch wants to size task_struct dynamically via arch_task_struct_size: diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts index cd316021d6ce..6c1b45c1af66 100644 --- a/arch/arm/boot/dts/armada-388-gp.dts +++ b/arch/arm/boot/dts/armada-388-gp.dts @@ -89,7 +89,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pca0_pins>; interrupt-parent = <&gpio0>; - interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -101,7 +101,7 @@ compatible = "nxp,pca9555"; pinctrl-names = "default"; interrupt-parent = <&gpio0>; - interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; interrupt-controller; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index faff7ea618d0..c944ecfa4eeb 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -172,10 +172,7 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ apq8098-v2.1-svr20.dtb \ msm8998-v2.1-interposer-sdm660-cdp.dtb \ msm8998-v2.1-interposer-sdm660-mtp.dtb \ - msm8998-v2.1-interposer-sdm660-qrd.dtb \ - msm8998-9x55-rcm.dtb \ - msm8998-9x55-cdp.dtb \ - msm8998-9x55-mtp.dtb + msm8998-v2.1-interposer-sdm660-qrd.dtb endif dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb diff --git a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi index d18344eb3daf..f1cf3136dbd0 100644 --- a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi @@ -44,6 +44,14 @@ gpios = <&tlmm 22 0>; status = "okay"; }; + + gpio_fan { + /* Based on 5v 75mA MC30100V2 */ + compatible = "gpio-fan"; + gpios = <&tlmm 43 GPIO_ACTIVE_LOW>; + gpio-fan,speed-map = <0 1>, + <8000 0>; + }; }; &soc { @@ -216,11 +224,18 @@ &spi_9 { status = "okay"; - /* CAN controller */ - spi@0 { - compatible = "nxp,mpc57xx"; + can-controller@0 { + compatible = "nxp,mpc5746c"; reg = <0>; - spi-max-frequency = <19200000>; + spi-max-frequency = <9600000>; + interrupt-parent = <&tlmm>; + interrupts = <78 0>; + reset-gpio = <&tlmm 71 GPIO_ACTIVE_LOW>; + bits-per-word = <8>; + reset-delay-msec = <100>; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&can_rst_on>; + pinctrl-1 = <&can_rst_off>; }; }; @@ -400,12 +415,6 @@ status = "okay"; }; -&tlmm { - /* Set these up as hogs */ - pinctrl-names = "default"; - pinctrl-0 = <&can_reset_gpio>; -}; - &pm8994_gpios { gpio@c700 { /* GPIO 8 - WLAN_EN */ qcom,mode = <1>; /* Digital output*/ diff --git a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi index d800fdaae3de..244901bd5cef 100644 --- a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi @@ -2745,17 +2745,32 @@ }; }; - can_reset_gpio: can_reset_gpio { - mux { - pins = "gpio71"; - function = "gpio"; + can_reset { + can_rst_on: rst_on { + mux { + pins = "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio71"; + drive-strength = <2>; /* 2 mA */ + bias-pull-up; + }; }; - config { - pins = "gpio71"; - drive-strength = <2>; - output-high; - bias-pull-up; + can_rst_off: rst_off { + mux { + pins = "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio71"; + drive-strength = <2>; /* 2 mA */ + bias-pull-up; + output-high; + }; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-9x55-cdp.dts b/arch/arm/boot/dts/qcom/msm8998-9x55-cdp.dts deleted file mode 100644 index cf167897bb89..000000000000 --- a/arch/arm/boot/dts/qcom/msm8998-9x55-cdp.dts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -/dts-v1/; - -#include "msm8998-9x55.dtsi" -#include "msm8998-mdss-panels.dtsi" -#include "msm8998-cdp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. MSM8998-9x55 CDP"; - compatible = "qcom,msm8998-9x55-cdp", "qcom,msm8998-9x55", "qcom,cdp"; - qcom,board-id= <1 2>; -}; diff --git a/arch/arm/boot/dts/qcom/msm8998-9x55-mtp.dts b/arch/arm/boot/dts/qcom/msm8998-9x55-mtp.dts deleted file mode 100644 index a95e9e4f272f..000000000000 --- a/arch/arm/boot/dts/qcom/msm8998-9x55-mtp.dts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -/dts-v1/; - -#include "msm8998-9x55.dtsi" -#include "msm8998-mdss-panels.dtsi" -#include "msm8998-mtp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. MSM8998-9x55 MTP"; - compatible = "qcom,msm8998-9x55-mtp", "qcom,msm8998-9x55", "qcom,mtp"; - qcom,board-id= <8 6>; -}; diff --git a/arch/arm/boot/dts/qcom/msm8998-9x55-rcm.dts b/arch/arm/boot/dts/qcom/msm8998-9x55-rcm.dts deleted file mode 100644 index 094ecbc50061..000000000000 --- a/arch/arm/boot/dts/qcom/msm8998-9x55-rcm.dts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -/dts-v1/; - -#include "msm8998-9x55.dtsi" -#include "msm8998-mdss-panels.dtsi" -#include "msm8998-cdp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. MSM8998-9x55 RCM"; - compatible = "qcom,msm8998-9x55-cdp", "qcom,msm8998-9x55", "qcom,cdp"; - qcom,board-id= <0x21 2>; -}; diff --git a/arch/arm/boot/dts/qcom/msm8998-9x55.dtsi b/arch/arm/boot/dts/qcom/msm8998-9x55.dtsi deleted file mode 100644 index be947507e398..000000000000 --- a/arch/arm/boot/dts/qcom/msm8998-9x55.dtsi +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 "skeleton64.dtsi" -#include "msm8998-v2.1.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. MSM8998-9x55"; - compatible = "qcom,msm8998-9x55"; - qcom,msm-id = <292 0x0>; - interrupt-parent = <&intc>; - - soc: soc { }; -}; diff --git a/arch/arm/boot/dts/qcom/msm8998-coresight.dtsi b/arch/arm/boot/dts/qcom/msm8998-coresight.dtsi index 4b81d2754255..24c91c6102a4 100644 --- a/arch/arm/boot/dts/qcom/msm8998-coresight.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-coresight.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -1412,6 +1412,14 @@ <&tpda_spss_out_funnel_spss>; }; }; + port@2 { + reg = <1>; + funnel_spss_in_spss_etm0: endpoint { + slave-mode; + remote-endpoint = + <&spss_etm0_out_funnel_spss>; + }; + }; }; }; @@ -1598,4 +1606,17 @@ }; }; }; + + dummy-spss-etm0 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-spss-etm0"; + + port{ + spss_etm0_out_funnel_spss: endpoint { + remote-endpoint = + <&funnel_spss_in_spss_etm0>; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/sda630-cdp.dts b/arch/arm/boot/dts/qcom/sda630-cdp.dts index 665fa94d9713..beefb2de1ce9 100644 --- a/arch/arm/boot/dts/qcom/sda630-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda630-cdp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sda630-cdp", "qcom,sda630", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda630-mtp.dts b/arch/arm/boot/dts/qcom/sda630-mtp.dts index 08a996ddb709..41afa720c389 100644 --- a/arch/arm/boot/dts/qcom/sda630-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda630-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sda630-mtp", "qcom,sda630", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts index 6094d22c1c92..01455d054e03 100644 --- a/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660A CDP"; compatible = "qcom,sda630-cdp", "qcom,sda630", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts index 49c10129aada..3dd15d889afd 100644 --- a/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660A MTP"; compatible = "qcom,sda630-mtp", "qcom,sda630", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts index 4c4c758daa29..155099b5be9d 100644 --- a/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660A QRD HDK630"; compatible = "qcom,sda630-qrd", "qcom,sda630", "qcom,qrd"; qcom,board-id = <0x0016000b 0x00>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &pm660a_oledb { diff --git a/arch/arm/boot/dts/qcom/sda636-cdp.dts b/arch/arm/boot/dts/qcom/sda636-cdp.dts index a4cc4b3f4662..2962a6bc3691 100644 --- a/arch/arm/boot/dts/qcom/sda636-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda636-cdp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sda636-cdp", "qcom,sda636", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda636-mtp.dts b/arch/arm/boot/dts/qcom/sda636-mtp.dts index 3fd19437b3eb..237d27791b94 100644 --- a/arch/arm/boot/dts/qcom/sda636-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda636-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sda636-mtp", "qcom,sda636", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts index 72db1be68c83..5f0e5275e828 100644 --- a/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A CDP"; compatible = "qcom,sda636-cdp", "qcom,sda636", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts index fd5b94420102..c15bc159dffd 100644 --- a/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A MTP"; compatible = "qcom,sda636-mtp", "qcom,sda636", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts index 3535c54f5dd0..f4a9592bf4ff 100644 --- a/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts @@ -158,7 +158,9 @@ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A QRD HDK636"; compatible = "qcom,sda636-qrd", "qcom,sda636", "qcom,qrd"; qcom,board-id = <0x0016000b 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &pm660a_oledb { diff --git a/arch/arm/boot/dts/qcom/sda658-cdp.dts b/arch/arm/boot/dts/qcom/sda658-cdp.dts index 9992963b8705..5db30e379a2d 100644 --- a/arch/arm/boot/dts/qcom/sda658-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda658-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,6 @@ compatible = "qcom,sda658-cdp", "qcom,sda658", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sda658-mtp.dts b/arch/arm/boot/dts/qcom/sda658-mtp.dts index f4322ecfd701..138c6fdc74df 100644 --- a/arch/arm/boot/dts/qcom/sda658-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda658-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,6 @@ compatible = "qcom,sda658-mtp", "qcom,sda658", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sda658-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda658-pm660a-cdp.dts index c280c4afda51..b4e7996e0bb6 100644 --- a/arch/arm/boot/dts/qcom/sda658-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda658-pm660a-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDA 658 PM660 + PM660A CDP"; compatible = "qcom,sda658-cdp", "qcom,sda658", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sda658-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda658-pm660a-mtp.dts index ba8741e2a068..52820a557ecf 100644 --- a/arch/arm/boot/dts/qcom/sda658-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda658-pm660a-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDA 658 PM660 + PM660A MTP"; compatible = "qcom,sda658-mtp", "qcom,sda658", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sda660-cdp.dts b/arch/arm/boot/dts/qcom/sda660-cdp.dts index 92097729087b..4299a0957455 100644 --- a/arch/arm/boot/dts/qcom/sda660-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda660-cdp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda660-mtp.dts b/arch/arm/boot/dts/qcom/sda660-mtp.dts index 027137e54c0e..71263375b1c0 100644 --- a/arch/arm/boot/dts/qcom/sda660-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda660-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sda660-mtp", "qcom,sda660", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts index a46083a00298..38900dab7596 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A CDP"; compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts index d94cf8ea1eb5..98ab098d6cdc 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A MTP"; compatible = "qcom,sda660-mtp", "qcom,sda660", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts index 0f4b462fd57b..5f44b4c32c98 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts @@ -158,7 +158,9 @@ model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A QRD HDK660"; compatible = "qcom,sda660-qrd", "qcom,sda660", "qcom,qrd"; qcom,board-id = <0x0016000b 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &pm660a_oledb { diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-cdp.dts index 973df0df3be5..8da3dd6726e6 100644 --- a/arch/arm/boot/dts/qcom/sdm630-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm630-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-headset-jacktype-no-cdp.dts index 4db377dc755a..27ef94e8a29a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-headset-jacktype-no-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-headset-jacktype-no-cdp.dts @@ -22,5 +22,6 @@ compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; qcom,board-id = <1 2>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts index baa55fa15160..39099ed1e97e 100644 --- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts @@ -22,5 +22,6 @@ compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; qcom,board-id = <1 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts index b469a59d7818..d9f30b41ed8e 100644 --- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm630-mtp", "qcom,sdm630", "qcom,mtp"; qcom,board-id = <8 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts index c4e71835b701..0ec2e17f10a5 100644 --- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts @@ -22,5 +22,7 @@ model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A Int. Audio Codec CDP"; compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; qcom,board-id = <1 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts index e11cdfbed668..d4f1214dc191 100644 --- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A Int. Audio Codec MTP"; compatible = "qcom,sdm630-mtp", "qcom,sdm630", "qcom,mtp"; qcom,board-id = <8 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-mtp.dts index b1a9bb86149d..3604ce486633 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm630-mtp", "qcom,sdm630", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts index 7e3e9a0cca59..a6f01eaa2a43 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A CDP"; compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-headset-jacktype-no-cdp.dts index 15936f47da7b..1596f7533581 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm660a-headset-jacktype-no-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-headset-jacktype-no-cdp.dts @@ -22,5 +22,7 @@ model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A, Headset Jacktype NO, CDP"; compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; qcom,board-id = <1 2>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts index a522b7ad1d5f..418b4a1e819f 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A MTP"; compatible = "qcom,sdm630-mtp", "qcom,sdm630", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts index deb10b591444..95b03f68b30f 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A QRD"; compatible = "qcom,sdm630-qrd", "qcom,sdm630", "qcom,qrd"; qcom,board-id = <0x0002000b 0x00>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm630-usbc-audio-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-usbc-audio-mtp.dts index eb089b524fef..309e9c6730a9 100644 --- a/arch/arm/boot/dts/qcom/sdm630-usbc-audio-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm630-usbc-audio-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm630-mtp", "qcom,sdm630", "qcom,mtp"; qcom,board-id = <8 2>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm636-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm636-camera-sensor-mtp.dtsi new file mode 100644 index 000000000000..ab6a7aebd6b9 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdm636-camera-sensor-mtp.dtsi @@ -0,0 +1,50 @@ +/* + * 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. + */ + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm660l_l8>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <3400000>; + qcom,cam-vreg-op-mode = <100000>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&pm660l_l8>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <3400000>; + qcom,cam-vreg-op-mode = <100000>; + }; + + actuator2: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&pm660l_l8>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <3400000>; + qcom,cam-vreg-op-mode = <100000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdm636-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-cdp.dts index 47f5eba8f491..ad1cac9c0c90 100644 --- a/arch/arm/boot/dts/qcom/sdm636-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-cdp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts index 4d47ac1ef517..c87ace6938bd 100644 --- a/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts @@ -22,5 +22,6 @@ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp"; qcom,board-id = <1 2>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts index 725e9739a487..1de6c4c13300 100644 --- a/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts @@ -22,5 +22,6 @@ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp"; qcom,board-id = <1 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts index 3630e329b13d..3522e67cf87e 100644 --- a/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp"; qcom,board-id = <8 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts index 416cd3754a10..e51c2e4709d2 100644 --- a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts @@ -22,5 +22,7 @@ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A Int. Audio Codec CDP"; compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp"; qcom,board-id = <1 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts index e9ad9048c6e9..e4d980a15a0d 100644 --- a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A Int. Audio Codec MTP"; compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp"; qcom,board-id = <8 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm636-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-mtp.dts index 7f08e44148b5..8ee5c46c804a 100644 --- a/arch/arm/boot/dts/qcom/sdm636-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi index f1d96459ec17..30174df3bd6a 100644 --- a/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi @@ -11,6 +11,7 @@ */ #include "sdm660-mtp.dtsi" +#include "sdm636-camera-sensor-mtp.dtsi" / { }; diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts index 84a28770d5a8..88d19d0c7bb1 100644 --- a/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A CDP"; compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &mdss_dsi { diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts index b2517e32ae26..b60fdc773941 100644 --- a/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A, Headset Jacktype NO, CDP"; compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp"; qcom,board-id = <1 2>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &mdss_dsi0 { diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts index 966a00af7216..6aaa8d070b42 100644 --- a/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A MTP"; compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &mdss_dsi { diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts index d8b6c744a204..68734c9cd8c6 100644 --- a/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts @@ -21,7 +21,9 @@ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A QRD"; compatible = "qcom,sdm636-qrd", "qcom,sdm636", "qcom,qrd"; qcom,board-id = <0x0012000b 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &pm660a_oledb { diff --git a/arch/arm/boot/dts/qcom/sdm636-qrd.dts b/arch/arm/boot/dts/qcom/sdm636-qrd.dts index a2d22f281a5d..b1977cdc50bc 100644 --- a/arch/arm/boot/dts/qcom/sdm636-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm636-qrd.dts @@ -21,7 +21,8 @@ compatible = "qcom,sdm636-qrd", "qcom,sdm636", "qcom,qrd"; qcom,board-id = <0x1000b 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &mdss_mdp { diff --git a/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts index 90879cdf35cc..8519a4891446 100644 --- a/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp"; qcom,board-id = <8 2>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm658-cdp.dts b/arch/arm/boot/dts/qcom/sdm658-cdp.dts index 8569af157049..223177aece50 100644 --- a/arch/arm/boot/dts/qcom/sdm658-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,6 @@ compatible = "qcom,sdm658-cdp", "qcom,sdm658", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm658-internal-codec-cdp.dts index d0f5c14223ff..c6cdf6e797af 100644 --- a/arch/arm/boot/dts/qcom/sdm658-internal-codec-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-internal-codec-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,7 +21,8 @@ compatible = "qcom,sdm658-cdp", "qcom,sdm658", "qcom,cdp"; qcom,board-id = <1 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &slim_aud { diff --git a/arch/arm/boot/dts/qcom/sdm658-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm658-internal-codec-mtp.dts index acec15e0615f..32203c9ccaee 100644 --- a/arch/arm/boot/dts/qcom/sdm658-internal-codec-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-internal-codec-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,7 +21,8 @@ compatible = "qcom,sdm658-mtp", "qcom,sdm658", "qcom,mtp"; qcom,board-id = <8 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &slim_aud { diff --git a/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-cdp.dts index b7f2e70ce962..a8d3de6f8962 100644 --- a/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDM 658 PM660 + PM660A Int. Audio Codec CDP"; compatible = "qcom,sdm658-cdp", "qcom,sdm658", "qcom,cdp"; qcom,board-id = <1 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-mtp.dts index 949d7ae7faa5..2689dc099f12 100644 --- a/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-internal-codec-pm660a-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDM 658 PM660 + PM660A Int. Audio Codec MTP"; compatible = "qcom,sdm658-mtp", "qcom,sdm658", "qcom,mtp"; qcom,board-id = <8 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-mtp.dts b/arch/arm/boot/dts/qcom/sdm658-mtp.dts index 2fbe9b0a6201..a57bba3b22af 100644 --- a/arch/arm/boot/dts/qcom/sdm658-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,6 @@ compatible = "qcom,sdm658-mtp", "qcom,sdm658", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm658-pm660a-cdp.dts index 39e2df958347..c719d76613b0 100644 --- a/arch/arm/boot/dts/qcom/sdm658-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-pm660a-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDM 658 PM660 + PM660A CDP"; compatible = "qcom,sdm658-cdp", "qcom,sdm658", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm658-pm660a-mtp.dts index 4d205ef403f4..4b6b7fa23710 100644 --- a/arch/arm/boot/dts/qcom/sdm658-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm658-pm660a-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDM 658 PM660 + PM660A MTP"; compatible = "qcom,sdm658-mtp", "qcom,sdm658", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm658-pm660a-qrd.dts index f1edf6b244a8..cd51a74ba18c 100644 --- a/arch/arm/boot/dts/qcom/sdm658-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm658-pm660a-qrd.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,7 @@ model = "Qualcomm Technologies, Inc. SDM 658 PM660 + PM660A QRD"; compatible = "qcom,sdm658-qrd", "qcom,sdm658", "qcom,qrd"; qcom,board-id = <0x1000b 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm658-qrd.dts b/arch/arm/boot/dts/qcom/sdm658-qrd.dts index bd7d76ee1f6c..155b730d52c3 100644 --- a/arch/arm/boot/dts/qcom/sdm658-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm658-qrd.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -21,5 +21,6 @@ compatible = "qcom,sdm658-qrd", "qcom,sdm658", "qcom,qrd"; qcom,board-id = <0x1000b 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-cdp.dts index 7b4b68af6188..1b634d7aaf56 100644 --- a/arch/arm/boot/dts/qcom/sdm660-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-cdp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; qcom,board-id = <1 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts index 48cfefb4cdd0..76755d99f6df 100644 --- a/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts @@ -22,5 +22,6 @@ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; qcom,board-id = <1 2>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts index 6755385313b1..a7020158c3a5 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-cdp.dts @@ -22,5 +22,6 @@ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; qcom,board-id = <1 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts index 39da13e7565b..4aeb561e7755 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; qcom,board-id = <8 1>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts index caf8af514237..780330c80565 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-cdp.dts @@ -22,5 +22,7 @@ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A Int. Audio Codec CDP"; compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; qcom,board-id = <1 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-mtp.dts index d2ae22879ef4..b9c8c900a973 100644 --- a/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-internal-codec-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A Int. Audio Codec MTP"; compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; qcom,board-id = <8 1>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &int_codec { diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-mtp.dts index 72bfa20b2bf9..32b294ee6883 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; qcom,board-id = <8 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts index c27f76d3027b..c20318c26373 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A CDP"; compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; qcom,board-id = <1 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &mdss_dsi { diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts index 281af3b1768e..5af607c0e1cc 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A, Headset Jacktype NO, CDP"; compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; qcom,board-id = <1 2>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &mdss_dsi0 { diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts index eb5e4999fb67..3aaa839e18be 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts @@ -22,7 +22,9 @@ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A MTP"; compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; qcom,board-id = <8 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &mdss_dsi { diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts index d9d74ea31d3d..848be11dc0a6 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts @@ -21,7 +21,9 @@ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A QRD"; compatible = "qcom,sdm660-qrd", "qcom,sdm660", "qcom,qrd"; qcom,board-id = <0x0012000b 0>; - qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; }; &pm660a_oledb { diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-qrd.dts index 4d120e83cb9b..3284e805a093 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dts @@ -21,7 +21,8 @@ compatible = "qcom,sdm660-qrd", "qcom,sdm660", "qcom,qrd"; qcom,board-id = <0x1000b 0>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &mdss_mdp { diff --git a/arch/arm/boot/dts/qcom/sdm660-usbc-audio-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-usbc-audio-mtp.dts index dff55d8e9cf8..b1a752b46a41 100644 --- a/arch/arm/boot/dts/qcom/sdm660-usbc-audio-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-usbc-audio-mtp.dts @@ -22,7 +22,8 @@ compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; qcom,board-id = <8 2>; qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, - <0x0001001b 0x0201011a 0x0 0x0>; + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; }; &tavil_snd { diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi index 1176b54835b1..045cc44b2d4c 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi @@ -22,6 +22,12 @@ qcom,ion-heap-type = "CARVEOUT"; }; + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + qcom,ion-heap@28 { /* Audio Heap */ reg = <28>; memory-region = <&ion_audio>; diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index 525dda6eb93e..af5adfeb1a41 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -677,6 +677,7 @@ CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y CONFIG_MEMTEST=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_FREE_PAGES_RDONLY=y diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index bfe2a2f5a644..22b73112b75f 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -54,6 +54,24 @@ static inline void *return_address(unsigned int level) #define ftrace_return_address(n) return_address(n) +#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME + +static inline bool arch_syscall_match_sym_name(const char *sym, + const char *name) +{ + if (!strcmp(sym, "sys_mmap2")) + sym = "sys_mmap_pgoff"; + else if (!strcmp(sym, "sys_statfs64_wrapper")) + sym = "sys_statfs64"; + else if (!strcmp(sym, "sys_fstatfs64_wrapper")) + sym = "sys_fstatfs64"; + else if (!strcmp(sym, "sys_arm_fadvise64_64")) + sym = "sys_fadvise64_64"; + + /* Ignore case since sym may start with "SyS" instead of "sys" */ + return !strcasecmp(sym, name); +} + #endif /* ifndef __ASSEMBLY__ */ #endif /* _ASM_ARM_FTRACE */ diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index e4a774f7aba1..360cea172b06 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -1636,12 +1636,16 @@ static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data) int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end) { + if (!kvm->arch.pgd) + return 0; trace_kvm_age_hva(start, end); return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL); } int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) { + if (!kvm->arch.pgd) + return 0; trace_kvm_test_age_hva(hva); return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL); } diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index a4aaba570d44..d61f3ae80e15 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -103,6 +103,7 @@ config ARM64 select SYSCTL_EXCEPTION_TRACE select HAVE_CONTEXT_TRACKING select HAVE_ARM_SMCCC + select THREAD_INFO_IN_TASK help ARM 64-bit (AArch64) Linux support. diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 28d10091da43..7e3bf18b06f7 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -220,6 +220,7 @@ CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_CAN=y CONFIG_CAN_RH850=y +CONFIG_CAN_K61=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_BTFM_SLIM=y @@ -334,6 +335,7 @@ CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_MSM_PM=y CONFIG_APSS_CORE_EA=y CONFIG_MSM_APM=y +CONFIG_SENSORS_GPIO_FAN=y CONFIG_SENSORS_EPM_ADC=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_LIMITS_MONITOR=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 1783707399ca..92fc522c11ed 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -222,6 +222,7 @@ CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_CAN=y CONFIG_CAN_RH850=y +CONFIG_CAN_K61=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_BTFM_SLIM=y @@ -337,6 +338,7 @@ CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_MSM_PM=y CONFIG_APSS_CORE_EA=y CONFIG_MSM_APM=y +CONFIG_SENSORS_GPIO_FAN=y CONFIG_SENSORS_EPM_ADC=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_LIMITS_MONITOR=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 77157bb85ee1..3cbcc10ceb1d 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -698,6 +698,7 @@ CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y CONFIG_MEMTEST=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index ac2e42ed36c0..7819916fb841 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -699,6 +699,7 @@ CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y CONFIG_MEMTEST=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 02e4b7e4bdbf..0e67a507dfbc 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -235,14 +235,25 @@ lr .req x30 // link register .endm /* + * @dst: Result of per_cpu(sym, smp_processor_id()) * @sym: The name of the per-cpu variable - * @reg: Result of per_cpu(sym, smp_processor_id()) * @tmp: scratch register */ - .macro this_cpu_ptr, sym, reg, tmp - adr_l \reg, \sym + .macro adr_this_cpu, dst, sym, tmp + adr_l \dst, \sym mrs \tmp, tpidr_el1 - add \reg, \reg, \tmp + add \dst, \dst, \tmp + .endm + + /* + * @dst: Result of READ_ONCE(per_cpu(sym, smp_processor_id())) + * @sym: The name of the per-cpu variable + * @tmp: scratch register + */ + .macro ldr_this_cpu dst, sym, tmp + adr_l \dst, \sym + mrs \tmp, tpidr_el1 + ldr \dst, [\dst, \tmp] .endm /* diff --git a/arch/arm64/include/asm/current.h b/arch/arm64/include/asm/current.h new file mode 100644 index 000000000000..2e61d21294ba --- /dev/null +++ b/arch/arm64/include/asm/current.h @@ -0,0 +1,27 @@ +#ifndef __ASM_CURRENT_H +#define __ASM_CURRENT_H + +#include <linux/compiler.h> + +#include <asm/sysreg.h> + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_THREAD_INFO_IN_TASK +struct task_struct; + +static __always_inline struct task_struct *get_current(void) +{ + return (struct task_struct *)read_sysreg(sp_el0); +} +#define current get_current() +#else +#include <linux/thread_info.h> +#define get_current() (current_thread_info()->task) +#define current get_current() +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_CURRENT_H */ + diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 8a336852eeba..2ce1a0262a59 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -16,6 +16,8 @@ #ifndef __ASM_PERCPU_H #define __ASM_PERCPU_H +#include <asm/stack_pointer.h> + static inline void set_my_cpu_offset(unsigned long off) { asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index da4397e14e0d..0c38c189fb3b 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -17,6 +17,8 @@ #ifndef __ASM_PERF_EVENT_H #define __ASM_PERF_EVENT_H +#include <asm/stack_pointer.h> + #ifdef CONFIG_PERF_EVENTS struct pt_regs; extern unsigned long perf_instruction_pointer(struct pt_regs *regs); diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 2013a4dc5124..a05033beb2a2 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -16,11 +16,20 @@ #ifndef __ASM_SMP_H #define __ASM_SMP_H +#include <asm/percpu.h> + #include <linux/threads.h> #include <linux/cpumask.h> #include <linux/thread_info.h> -#define raw_smp_processor_id() (current_thread_info()->cpu) +DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number); + +/* + * We don't use this_cpu_read(cpu_number) as that has implicit writes to + * preempt_count, and associated (compiler) barriers, that we'd like to avoid + * the expense of. If we're preemptible, the value can be stale at use anyway. + */ +#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number)) struct seq_file; @@ -57,6 +66,9 @@ asmlinkage void secondary_start_kernel(void); */ struct secondary_data { void *stack; +#ifdef CONFIG_THREAD_INFO_IN_TASK + struct task_struct *task; +#endif }; extern struct secondary_data secondary_data; extern void secondary_entry(void); diff --git a/arch/arm64/include/asm/stack_pointer.h b/arch/arm64/include/asm/stack_pointer.h new file mode 100644 index 000000000000..ffcdf742cddf --- /dev/null +++ b/arch/arm64/include/asm/stack_pointer.h @@ -0,0 +1,9 @@ +#ifndef __ASM_STACK_POINTER_H +#define __ASM_STACK_POINTER_H + +/* + * how to get the current stack pointer from C + */ +register unsigned long current_stack_pointer asm ("sp"); + +#endif /* __ASM_STACK_POINTER_H */ diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index 024d623f662e..92d6a628e478 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h @@ -1,7 +1,7 @@ #ifndef __ASM_SUSPEND_H #define __ASM_SUSPEND_H -#define NR_CTX_REGS 10 +#define NR_CTX_REGS 12 #define NR_CALLEE_SAVED_REGS 12 /* diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 4bb038ec6453..db6d058ab0f3 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -36,25 +36,36 @@ struct task_struct; +#include <asm/stack_pointer.h> #include <asm/types.h> typedef unsigned long mm_segment_t; /* * low level task data that entry.S needs immediate access to. - * __switch_to() assumes cpu_context follows immediately after cpu_domain. */ struct thread_info { unsigned long flags; /* low level flags */ mm_segment_t addr_limit; /* address limit */ +#ifndef CONFIG_THREAD_INFO_IN_TASK struct task_struct *task; /* main task structure */ +#endif #ifdef CONFIG_ARM64_SW_TTBR0_PAN u64 ttbr0; /* saved TTBR0_EL1 */ #endif int preempt_count; /* 0 => preemptable, <0 => bug */ +#ifndef CONFIG_THREAD_INFO_IN_TASK int cpu; /* cpu */ +#endif }; +#ifdef CONFIG_THREAD_INFO_IN_TASK +#define INIT_THREAD_INFO(tsk) \ +{ \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ +} +#else #define INIT_THREAD_INFO(tsk) \ { \ .task = &tsk, \ @@ -63,14 +74,6 @@ struct thread_info { .addr_limit = KERNEL_DS, \ } -#define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) - -/* - * how to get the current stack pointer from C - */ -register unsigned long current_stack_pointer asm ("sp"); - /* * how to get the thread information struct from C */ @@ -88,6 +91,11 @@ static inline struct thread_info *current_thread_info(void) return (struct thread_info *)sp_el0; } +#define init_thread_info (init_thread_union.thread_info) +#endif + +#define init_stack (init_thread_union.stack) + #define thread_saved_pc(tsk) \ ((unsigned long)(tsk->thread.cpu_context.pc)) #define thread_saved_sp(tsk) \ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 350c0e99fc6b..36c4307c4af3 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -35,11 +35,16 @@ int main(void) { DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); BLANK(); +#ifdef CONFIG_THREAD_INFO_IN_TASK + DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); + DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); + DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); + DEFINE(TSK_STACK, offsetof(struct task_struct, stack)); +#else DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); - DEFINE(TI_TASK, offsetof(struct thread_info, task)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); +#endif #ifdef CONFIG_ARM64_SW_TTBR0_PAN DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0)); #endif @@ -124,6 +129,11 @@ int main(void) DEFINE(TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); BLANK(); +#ifdef CONFIG_THREAD_INFO_IN_TASK + DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack)); + DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); + BLANK(); +#endif #ifdef CONFIG_KVM_ARM_HOST DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt)); DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs)); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 7822e36d87fb..381f9febcdb6 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -93,9 +93,14 @@ .if \el == 0 mrs x21, sp_el0 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear, + ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug +#else mov tsk, sp and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear, ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug +#endif disable_step_tsk x19, x20 // exceptions when scheduling. mov x29, xzr // fp pointed to user-space @@ -103,10 +108,18 @@ add x21, sp, #S_FRAME_SIZE get_thread_info tsk /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */ +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x20, [tsk, #TSK_TI_ADDR_LIMIT] +#else ldr x20, [tsk, #TI_ADDR_LIMIT] +#endif str x20, [sp, #S_ORIG_ADDR_LIMIT] mov x20, #TASK_SIZE_64 +#ifdef CONFIG_THREAD_INFO_IN_TASK + str x20, [tsk, #TSK_TI_ADDR_LIMIT] +#else str x20, [tsk, #TI_ADDR_LIMIT] +#endif ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO) .endif /* \el == 0 */ mrs x22, elr_el1 @@ -168,7 +181,11 @@ alternative_else_nop_endif .if \el != 0 /* Restore the task's original addr_limit. */ ldr x20, [sp, #S_ORIG_ADDR_LIMIT] +#ifdef CONFIG_THREAD_INFO_IN_TASK + str x20, [tsk, #TSK_TI_ADDR_LIMIT] +#else str x20, [tsk, #TI_ADDR_LIMIT] +#endif /* No need to restore UAO, it will be restored from SPSR_EL1 */ .endif @@ -258,15 +275,22 @@ alternative_endif mov x19, sp // preserve the original sp /* - * Compare sp with the current thread_info, if the top - * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and - * should switch to the irq stack. + * Compare sp with the base of the task stack. + * If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack, + * and should switch to the irq stack. */ +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x25, [tsk, TSK_STACK] + eor x25, x25, x19 + and x25, x25, #~(THREAD_SIZE - 1) + cbnz x25, 9998f +#else and x25, x19, #~(THREAD_SIZE - 1) cmp x25, tsk b.ne 9998f +#endif - this_cpu_ptr irq_stack, x25, x26 + adr_this_cpu x25, irq_stack, x26 mov x26, #IRQ_STACK_START_SP add x26, x25, x26 @@ -498,9 +522,17 @@ el1_irq: irq_handler #ifdef CONFIG_PREEMPT +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count +#else ldr w24, [tsk, #TI_PREEMPT] // get preempt count +#endif cbnz w24, 1f // preempt count != 0 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x0, [tsk, #TSK_TI_FLAGS] // get flags +#else ldr x0, [tsk, #TI_FLAGS] // get flags +#endif tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? bl el1_preempt 1: @@ -515,7 +547,11 @@ ENDPROC(el1_irq) el1_preempt: mov x24, lr 1: bl preempt_schedule_irq // irq en/disable is done inside +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS +#else ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS +#endif tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling? ret x24 #endif @@ -773,8 +809,12 @@ ENTRY(cpu_switch_to) mov v15.16b, v15.16b #endif mov sp, x9 +#ifdef CONFIG_THREAD_INFO_IN_TASK + msr sp_el0, x1 +#else and x9, x9, #~(THREAD_SIZE - 1) msr sp_el0, x9 +#endif ret ENDPROC(cpu_switch_to) @@ -785,7 +825,11 @@ ENDPROC(cpu_switch_to) ret_fast_syscall: disable_irq // disable interrupts str x0, [sp, #S_X0] // returned x0 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing +#else ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing +#endif and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace and x2, x1, #_TIF_WORK_MASK @@ -817,7 +861,11 @@ work_resched: */ ret_to_user: disable_irq // disable interrupts +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x1, [tsk, #TSK_TI_FLAGS] +#else ldr x1, [tsk, #TI_FLAGS] +#endif and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending enable_step_tsk x1, x2 @@ -849,7 +897,11 @@ el0_svc_naked: // compat entry point enable_dbg_and_irq ct_user_exit 1 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks +#else ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks +#endif tst x16, #_TIF_SYSCALL_WORK b.ne __sys_trace cmp scno, sc_nr // check upper syscall limit diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index a1c2ac38771d..0a0cd0476665 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -418,6 +418,7 @@ ENDPROC(__create_page_tables) .set initial_sp, init_thread_union + THREAD_START_SP __primary_switched: mov x28, lr // preserve LR + adr_l x8, vectors // load VBAR_EL1 with virtual msr vbar_el1, x8 // vector table address isb @@ -430,10 +431,18 @@ __primary_switched: bl __pi_memset dsb ishst // Make zero page visible to PTW +#ifdef CONFIG_THREAD_INFO_IN_TASK + adrp x4, init_thread_union + add sp, x4, #THREAD_SIZE + adr_l x5, init_task + msr sp_el0, x5 // Save thread_info +#else adr_l sp, initial_sp, x4 mov x4, sp and x4, x4, #~(THREAD_SIZE - 1) msr sp_el0, x4 // Save thread_info +#endif + str_l x21, __fdt_pointer, x5 // Save FDT pointer ldr_l x4, kimage_vaddr // Save the offset between @@ -642,11 +651,18 @@ __secondary_switched: adr_l x5, vectors msr vbar_el1, x5 isb - +#ifdef CONFIG_THREAD_INFO_IN_TASK + adr_l x0, secondary_data + ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack + mov sp, x1 + ldr x2, [x0, #CPU_BOOT_TASK] + msr sp_el0, x2 +#else ldr_l x0, secondary_data // get secondary_data.stack mov sp, x0 and x0, x0, #~(THREAD_SIZE - 1) msr sp_el0, x0 // save thread_info +#endif mov x29, #0 b secondary_start_kernel ENDPROC(__secondary_switched) diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c index dc92b29ac103..7b852e36eaa2 100644 --- a/arch/arm64/kernel/perf_trace_counters.c +++ b/arch/arm64/kernel/perf_trace_counters.c @@ -65,7 +65,7 @@ void tracectr_notifier(void *ignore, bool preempt, { u32 cnten_val; int current_pid; - u32 cpu = task_thread_info(next)->cpu; + u32 cpu = task_cpu(next); if (tp_pid_state != 1) return; diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index fc0a7aa2ca82..9918489f5af3 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -45,6 +45,9 @@ #include <linux/personality.h> #include <linux/notifier.h> #include <trace/events/power.h> +#ifdef CONFIG_THREAD_INFO_IN_TASK +#include <linux/percpu.h> +#endif #include <asm/alternative.h> #include <asm/compat.h> @@ -394,6 +397,22 @@ void uao_thread_switch(struct task_struct *next) } } +#ifdef CONFIG_THREAD_INFO_IN_TASK +/* + * We store our current task in sp_el0, which is clobbered by userspace. Keep a + * shadow copy so that we can restore this upon entry from userspace. + * + * This is *only* for exception entry from EL0, and is not valid until we + * __switch_to() a user task. + */ +DEFINE_PER_CPU(struct task_struct *, __entry_task); + +static void entry_task_switch(struct task_struct *next) +{ + __this_cpu_write(__entry_task, next); +} +#endif + /* * Thread switching. */ @@ -406,6 +425,9 @@ struct task_struct *__switch_to(struct task_struct *prev, tls_thread_switch(next); hw_breakpoint_thread_switch(next); contextidr_thread_switch(next); +#ifdef CONFIG_THREAD_INFO_IN_TASK + entry_task_switch(next); +#endif uao_thread_switch(next); /* @@ -423,27 +445,35 @@ struct task_struct *__switch_to(struct task_struct *prev, unsigned long get_wchan(struct task_struct *p) { struct stackframe frame; - unsigned long stack_page; + unsigned long stack_page, ret = 0; int count = 0; if (!p || p == current || p->state == TASK_RUNNING) return 0; + stack_page = (unsigned long)try_get_task_stack(p); + if (!stack_page) + return 0; + frame.fp = thread_saved_fp(p); frame.sp = thread_saved_sp(p); frame.pc = thread_saved_pc(p); #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = p->curr_ret_stack; #endif - stack_page = (unsigned long)task_stack_page(p); do { if (frame.sp < stack_page || frame.sp >= stack_page + THREAD_SIZE || unwind_frame(p, &frame)) - return 0; - if (!in_sched_functions(frame.pc)) - return frame.pc; + goto out; + if (!in_sched_functions(frame.pc)) { + ret = frame.pc; + goto out; + } } while (count ++ < 16); - return 0; + +out: + put_task_stack(p); + return ret; } unsigned long arch_align_stack(unsigned long sp) diff --git a/arch/arm64/kernel/return_address.c b/arch/arm64/kernel/return_address.c index 1718706fde83..12a87f2600f2 100644 --- a/arch/arm64/kernel/return_address.c +++ b/arch/arm64/kernel/return_address.c @@ -12,6 +12,7 @@ #include <linux/export.h> #include <linux/ftrace.h> +#include <asm/stack_pointer.h> #include <asm/stacktrace.h> struct return_address_data { diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 30af178c640c..f592e7406fc5 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -362,11 +362,15 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_ARM64_SW_TTBR0_PAN /* - * Make sure init_thread_info.ttbr0 always generates translation + * Make sure thread_info.ttbr0 always generates translation * faults in case uaccess_enable() is inadvertently called by the init * thread. */ - init_thread_info.ttbr0 = virt_to_phys(empty_zero_page); +#ifdef CONFIG_THREAD_INFO_IN_TASK + init_task.thread_info.ttbr0 = virt_to_phys(empty_zero_page); +#else + init_thread_info.ttbr0 = (init_thread_union.thread_info); +#endif #endif #ifdef CONFIG_VT diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 9a3aec97ac09..9e3cb29e4c50 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -124,9 +124,6 @@ ENTRY(_cpu_resume) /* load sp from context */ ldr x2, [x0, #CPU_CTX_SP] mov sp, x2 - /* save thread_info */ - and x2, x2, #~(THREAD_SIZE - 1) - msr sp_el0, x2 /* * cpu_do_resume expects x0 to contain context address pointer */ diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d031a85e0bc7..961fd5d2e7ce 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -59,6 +59,9 @@ #define CREATE_TRACE_POINTS #include <trace/events/ipi.h> +DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); +EXPORT_PER_CPU_SYMBOL(cpu_number); + /* * as from 2.5, kernels no longer have an init_tasks structure * so we need some other way of telling a new secondary core @@ -98,6 +101,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) * We need to tell the secondary core where to find its stack and the * page tables. */ +#ifdef CONFIG_THREAD_INFO_IN_TASK + secondary_data.task = idle; +#endif secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; __flush_dcache_area(&secondary_data, sizeof(secondary_data)); @@ -121,6 +127,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) pr_err("CPU%u: failed to boot: %d\n", cpu, ret); } +#ifdef CONFIG_THREAD_INFO_IN_TASK + secondary_data.task = NULL; +#endif secondary_data.stack = NULL; return ret; @@ -138,7 +147,12 @@ static void smp_store_cpu_info(unsigned int cpuid) asmlinkage void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + cpu = task_cpu(current); + set_my_cpu_offset(per_cpu_offset(cpu)); + + pr_debug("CPU%u: Booted secondary processor\n", cpu); /* * All kernel threads share the same mm context; grab a @@ -147,10 +161,6 @@ asmlinkage void secondary_start_kernel(void) atomic_inc(&mm->mm_count); current->active_mm = mm; - set_my_cpu_offset(per_cpu_offset(smp_processor_id())); - - pr_debug("CPU%u: Booted secondary processor\n", cpu); - /* * TTBR0 is only used for the identity mapping at this stage. Make it * point to zero page to avoid speculatively fetching new entries. @@ -633,6 +643,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (max_cpus == 0) break; + per_cpu(cpu_number, cpu) = cpu; + if (cpu == smp_processor_id()) continue; diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 1fd1a9a6596f..ea3e453fdd14 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -23,6 +23,7 @@ #include <linux/stacktrace.h> #include <asm/irq.h> +#include <asm/stack_pointer.h> #include <asm/stacktrace.h> /* @@ -130,7 +131,6 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, break; } } -EXPORT_SYMBOL(walk_stackframe); #ifdef CONFIG_STACKTRACE struct stack_trace_data { @@ -162,6 +162,9 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) struct stack_trace_data data; struct stackframe frame; + if (!try_get_task_stack(tsk)) + return; + data.trace = trace; data.skip = trace->skip; @@ -183,6 +186,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) walk_stackframe(tsk, &frame, save_trace, &data); if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; + + put_task_stack(tsk); } EXPORT_SYMBOL(save_stack_trace_tsk); diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 0acdb63d19b6..468b939f3471 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -45,12 +45,6 @@ void notrace __cpu_suspend_exit(void) cpu_uninstall_idmap(); /* - * Restore per-cpu offset before any kernel - * subsystem relying on it has a chance to run. - */ - set_my_cpu_offset(per_cpu_offset(smp_processor_id())); - - /* * Restore HW breakpoint registers to sane values * before debug exceptions are possibly reenabled * through local_dbg_restore. diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index f4ab8bc661da..ea40dc101433 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -38,6 +38,7 @@ #include <asm/esr.h> #include <asm/insn.h> #include <asm/traps.h> +#include <asm/stack_pointer.h> #include <asm/stacktrace.h> #include <asm/exception.h> #include <asm/system_misc.h> @@ -153,6 +154,14 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) unsigned long irq_stack_ptr; int skip; + pr_debug("%s(regs = %pK tsk = %pK)\n", __func__, regs, tsk); + + if (!tsk) + tsk = current; + + if (!try_get_task_stack(tsk)) + return; + /* * Switching between stacks is valid when tracing current and in * non-preemptible context. @@ -223,6 +232,8 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) stack + sizeof(struct pt_regs), false); } } + + put_task_stack(tsk); } void show_stack(struct task_struct *tsk, unsigned long *sp) @@ -238,10 +249,9 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) #endif #define S_SMP " SMP" -static int __die(const char *str, int err, struct thread_info *thread, - struct pt_regs *regs) +static int __die(const char *str, int err, struct pt_regs *regs) { - struct task_struct *tsk = thread->task; + struct task_struct *tsk = current; static int die_counter; int ret; @@ -256,7 +266,8 @@ static int __die(const char *str, int err, struct thread_info *thread, print_modules(); __show_regs(regs); pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n", - TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1); + TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), + end_of_stack(tsk)); if (!user_mode(regs) || in_interrupt()) { dump_backtrace(regs, tsk); @@ -321,7 +332,6 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, int notify) */ void die(const char *str, struct pt_regs *regs, int err) { - struct thread_info *thread = current_thread_info(); enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE; unsigned long flags = oops_begin(); int ret; @@ -331,7 +341,7 @@ void die(const char *str, struct pt_regs *regs, int err) if (bug_type != BUG_TRAP_TYPE_NONE) str = "Oops - BUG"; - ret = __die(str, err, thread, regs); + ret = __die(str, err, regs); oops_end(flags, regs, ret); } diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 81a0de4e457d..d780180106c1 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -116,11 +116,14 @@ ENTRY(cpu_do_suspend) mrs x8, mdscr_el1 mrs x9, oslsr_el1 mrs x10, sctlr_el1 + mrs x11, tpidr_el1 + mrs x12, sp_el0 stp x2, x3, [x0] stp x4, xzr, [x0, #16] stp x5, x6, [x0, #32] stp x7, x8, [x0, #48] stp x9, x10, [x0, #64] + stp x11, x12, [x0, #80] ret ENDPROC(cpu_do_suspend) @@ -135,6 +138,7 @@ ENTRY(cpu_do_resume) ldp x6, x8, [x0, #32] ldp x9, x10, [x0, #48] ldp x11, x12, [x0, #64] + ldp x13, x14, [x0, #80] msr tpidr_el0, x2 msr tpidrro_el0, x3 msr contextidr_el1, x4 @@ -148,6 +152,8 @@ ENTRY(cpu_do_resume) msr vbar_el1, x9 msr mdscr_el1, x10 msr sctlr_el1, x12 + msr tpidr_el1, x13 + msr sp_el0, x14 /* * Restore oslsr_el1 by writing oslar_el1 */ diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 2c86a4ef6742..7091a367eeda 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -45,7 +45,7 @@ config IA64 select GENERIC_SMP_IDLE_THREAD select ARCH_INIT_TASK select ARCH_TASK_STRUCT_ALLOCATOR - select ARCH_THREAD_INFO_ALLOCATOR + select ARCH_THREAD_STACK_ALLOCATOR select ARCH_CLOCKSOURCE_DATA select GENERIC_TIME_VSYSCALL_OLD select SYSCTL_ARCH_UNALIGN_NO_WARN diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h index aa995b67c3f5..d1212b84fb83 100644 --- a/arch/ia64/include/asm/thread_info.h +++ b/arch/ia64/include/asm/thread_info.h @@ -48,15 +48,15 @@ struct thread_info { #ifndef ASM_OFFSETS_C /* how to get the thread information struct from C */ #define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE)) -#define alloc_thread_info_node(tsk, node) \ - ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE)) +#define alloc_thread_stack_node(tsk, node) \ + ((unsigned long *) ((char *) (tsk) + IA64_TASK_SIZE)) #define task_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE)) #else #define current_thread_info() ((struct thread_info *) 0) -#define alloc_thread_info_node(tsk, node) ((struct thread_info *) 0) +#define alloc_thread_stack_node(tsk, node) ((unsigned long *) 0) #define task_thread_info(tsk) ((struct thread_info *) 0) #endif -#define free_thread_info(ti) /* nothing */ +#define free_thread_stack(ti) /* nothing */ #define task_stack_page(tsk) ((void *)(tsk)) #define __HAVE_THREAD_FUNCTIONS diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c index f9efe9739d3f..0eaa89f3defd 100644 --- a/arch/ia64/kernel/init_task.c +++ b/arch/ia64/kernel/init_task.c @@ -26,6 +26,7 @@ static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); * handled. This is done by having a special ".data..init_task" section... */ #define init_thread_info init_task_mem.s.thread_info +#define init_stack init_task_mem.stack union { struct { diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h index 4861a78c7160..f5f90bbf019d 100644 --- a/arch/mn10300/include/asm/thread_info.h +++ b/arch/mn10300/include/asm/thread_info.h @@ -115,7 +115,7 @@ static inline unsigned long current_stack_pointer(void) } #ifndef CONFIG_KGDB -void arch_release_thread_info(struct thread_info *ti); +void arch_release_thread_stack(unsigned long *stack); #endif #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) diff --git a/arch/mn10300/kernel/kgdb.c b/arch/mn10300/kernel/kgdb.c index 99770823451a..2d7986c386fe 100644 --- a/arch/mn10300/kernel/kgdb.c +++ b/arch/mn10300/kernel/kgdb.c @@ -397,8 +397,9 @@ static bool kgdb_arch_undo_singlestep(struct pt_regs *regs) * single-step state is cleared. At this point the breakpoints should have * been removed by __switch_to(). */ -void arch_release_thread_info(struct thread_info *ti) +void arch_release_thread_stack(unsigned long *stack) { + struct thread_info *ti = (void *)stack; if (kgdb_sstep_thread == ti) { kgdb_sstep_thread = NULL; diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 0e2919dd8df3..1395eeb6005f 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -1250,7 +1250,8 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp) insn_count = bpf_jit_insn(jit, fp, i); if (insn_count < 0) return -1; - jit->addrs[i + 1] = jit->prg; /* Next instruction address */ + /* Next instruction address */ + jit->addrs[i + insn_count] = jit->prg; } bpf_jit_epilogue(jit); diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 349dd23e2876..0cdeb2b483a0 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -25,9 +25,11 @@ void destroy_context(struct mm_struct *mm); void __tsb_context_switch(unsigned long pgd_pa, struct tsb_config *tsb_base, struct tsb_config *tsb_huge, - unsigned long tsb_descr_pa); + unsigned long tsb_descr_pa, + unsigned long secondary_ctx); -static inline void tsb_context_switch(struct mm_struct *mm) +static inline void tsb_context_switch_ctx(struct mm_struct *mm, + unsigned long ctx) { __tsb_context_switch(__pa(mm->pgd), &mm->context.tsb_block[0], @@ -38,9 +40,12 @@ static inline void tsb_context_switch(struct mm_struct *mm) #else NULL #endif - , __pa(&mm->context.tsb_descr[0])); + , __pa(&mm->context.tsb_descr[0]), + ctx); } +#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0) + void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long mm_rss); @@ -110,8 +115,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str * cpu0 to update it's TSB because at that point the cpu_vm_mask * only had cpu1 set in it. */ - load_secondary_context(mm); - tsb_context_switch(mm); + tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context)); /* Any time a processor runs a context on an address space * for the first time, we must flush that context out of the diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h index ec9c04de3664..ff05992dae7a 100644 --- a/arch/sparc/include/asm/trap_block.h +++ b/arch/sparc/include/asm/trap_block.h @@ -54,6 +54,7 @@ extern struct trap_per_cpu trap_block[NR_CPUS]; void init_cur_cpu_trap(struct thread_info *); void setup_tba(void); extern int ncpus_probed; +extern u64 cpu_mondo_counter[NR_CPUS]; unsigned long real_hard_smp_processor_id(void); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 95a9fa0d2195..4511caa3b7e9 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -617,22 +617,48 @@ retry: } } -/* Multi-cpu list version. */ +#define CPU_MONDO_COUNTER(cpuid) (cpu_mondo_counter[cpuid]) +#define MONDO_USEC_WAIT_MIN 2 +#define MONDO_USEC_WAIT_MAX 100 +#define MONDO_RETRY_LIMIT 500000 + +/* Multi-cpu list version. + * + * Deliver xcalls to 'cnt' number of cpus in 'cpu_list'. + * Sometimes not all cpus receive the mondo, requiring us to re-send + * the mondo until all cpus have received, or cpus are truly stuck + * unable to receive mondo, and we timeout. + * Occasionally a target cpu strand is borrowed briefly by hypervisor to + * perform guest service, such as PCIe error handling. Consider the + * service time, 1 second overall wait is reasonable for 1 cpu. + * Here two in-between mondo check wait time are defined: 2 usec for + * single cpu quick turn around and up to 100usec for large cpu count. + * Deliver mondo to large number of cpus could take longer, we adjusts + * the retry count as long as target cpus are making forward progress. + */ static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt) { - int retries, this_cpu, prev_sent, i, saw_cpu_error; + int this_cpu, tot_cpus, prev_sent, i, rem; + int usec_wait, retries, tot_retries; + u16 first_cpu = 0xffff; + unsigned long xc_rcvd = 0; unsigned long status; + int ecpuerror_id = 0; + int enocpu_id = 0; u16 *cpu_list; + u16 cpu; this_cpu = smp_processor_id(); - cpu_list = __va(tb->cpu_list_pa); - - saw_cpu_error = 0; - retries = 0; + usec_wait = cnt * MONDO_USEC_WAIT_MIN; + if (usec_wait > MONDO_USEC_WAIT_MAX) + usec_wait = MONDO_USEC_WAIT_MAX; + retries = tot_retries = 0; + tot_cpus = cnt; prev_sent = 0; + do { - int forward_progress, n_sent; + int n_sent, mondo_delivered, target_cpu_busy; status = sun4v_cpu_mondo_send(cnt, tb->cpu_list_pa, @@ -640,94 +666,113 @@ static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt) /* HV_EOK means all cpus received the xcall, we're done. */ if (likely(status == HV_EOK)) - break; + goto xcall_done; + + /* If not these non-fatal errors, panic */ + if (unlikely((status != HV_EWOULDBLOCK) && + (status != HV_ECPUERROR) && + (status != HV_ENOCPU))) + goto fatal_errors; /* First, see if we made any forward progress. * + * Go through the cpu_list, count the target cpus that have + * received our mondo (n_sent), and those that did not (rem). + * Re-pack cpu_list with the cpus remain to be retried in the + * front - this simplifies tracking the truly stalled cpus. + * * The hypervisor indicates successful sends by setting * cpu list entries to the value 0xffff. + * + * EWOULDBLOCK means some target cpus did not receive the + * mondo and retry usually helps. + * + * ECPUERROR means at least one target cpu is in error state, + * it's usually safe to skip the faulty cpu and retry. + * + * ENOCPU means one of the target cpu doesn't belong to the + * domain, perhaps offlined which is unexpected, but not + * fatal and it's okay to skip the offlined cpu. */ + rem = 0; n_sent = 0; for (i = 0; i < cnt; i++) { - if (likely(cpu_list[i] == 0xffff)) + cpu = cpu_list[i]; + if (likely(cpu == 0xffff)) { n_sent++; + } else if ((status == HV_ECPUERROR) && + (sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) { + ecpuerror_id = cpu + 1; + } else if (status == HV_ENOCPU && !cpu_online(cpu)) { + enocpu_id = cpu + 1; + } else { + cpu_list[rem++] = cpu; + } } - forward_progress = 0; - if (n_sent > prev_sent) - forward_progress = 1; + /* No cpu remained, we're done. */ + if (rem == 0) + break; - prev_sent = n_sent; + /* Otherwise, update the cpu count for retry. */ + cnt = rem; - /* If we get a HV_ECPUERROR, then one or more of the cpus - * in the list are in error state. Use the cpu_state() - * hypervisor call to find out which cpus are in error state. + /* Record the overall number of mondos received by the + * first of the remaining cpus. */ - if (unlikely(status == HV_ECPUERROR)) { - for (i = 0; i < cnt; i++) { - long err; - u16 cpu; + if (first_cpu != cpu_list[0]) { + first_cpu = cpu_list[0]; + xc_rcvd = CPU_MONDO_COUNTER(first_cpu); + } - cpu = cpu_list[i]; - if (cpu == 0xffff) - continue; + /* Was any mondo delivered successfully? */ + mondo_delivered = (n_sent > prev_sent); + prev_sent = n_sent; - err = sun4v_cpu_state(cpu); - if (err == HV_CPU_STATE_ERROR) { - saw_cpu_error = (cpu + 1); - cpu_list[i] = 0xffff; - } - } - } else if (unlikely(status != HV_EWOULDBLOCK)) - goto fatal_mondo_error; + /* or, was any target cpu busy processing other mondos? */ + target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu)); + xc_rcvd = CPU_MONDO_COUNTER(first_cpu); - /* Don't bother rewriting the CPU list, just leave the - * 0xffff and non-0xffff entries in there and the - * hypervisor will do the right thing. - * - * Only advance timeout state if we didn't make any - * forward progress. + /* Retry count is for no progress. If we're making progress, + * reset the retry count. */ - if (unlikely(!forward_progress)) { - if (unlikely(++retries > 10000)) - goto fatal_mondo_timeout; - - /* Delay a little bit to let other cpus catch up - * on their cpu mondo queue work. - */ - udelay(2 * cnt); + if (likely(mondo_delivered || target_cpu_busy)) { + tot_retries += retries; + retries = 0; + } else if (unlikely(retries > MONDO_RETRY_LIMIT)) { + goto fatal_mondo_timeout; } - } while (1); - if (unlikely(saw_cpu_error)) - goto fatal_mondo_cpu_error; + /* Delay a little bit to let other cpus catch up on + * their cpu mondo queue work. + */ + if (!mondo_delivered) + udelay(usec_wait); - return; + retries++; + } while (1); -fatal_mondo_cpu_error: - printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " - "(including %d) were in error state\n", - this_cpu, saw_cpu_error - 1); +xcall_done: + if (unlikely(ecpuerror_id > 0)) { + pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n", + this_cpu, ecpuerror_id - 1); + } else if (unlikely(enocpu_id > 0)) { + pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n", + this_cpu, enocpu_id - 1); + } return; +fatal_errors: + /* fatal errors include bad alignment, etc */ + pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n", + this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa); + panic("Unexpected SUN4V mondo error %lu\n", status); + fatal_mondo_timeout: - printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " - " progress after %d retries.\n", - this_cpu, retries); - goto dump_cpu_list_and_out; - -fatal_mondo_error: - printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", - this_cpu, status); - printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " - "mondo_block_pa(%lx)\n", - this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa); - -dump_cpu_list_and_out: - printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu); - for (i = 0; i < cnt; i++) - printk("%u ", cpu_list[i]); - printk("]\n"); + /* some cpus being non-responsive to the cpu mondo */ + pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n", + this_cpu, first_cpu, (tot_retries + retries), tot_cpus); + panic("SUN4V mondo timeout panic\n"); } static void (*xcall_deliver_impl)(struct trap_per_cpu *, int); diff --git a/arch/sparc/kernel/sun4v_ivec.S b/arch/sparc/kernel/sun4v_ivec.S index 559bc5e9c199..34631995859a 100644 --- a/arch/sparc/kernel/sun4v_ivec.S +++ b/arch/sparc/kernel/sun4v_ivec.S @@ -26,6 +26,21 @@ sun4v_cpu_mondo: ldxa [%g0] ASI_SCRATCHPAD, %g4 sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4 + /* Get smp_processor_id() into %g3 */ + sethi %hi(trap_block), %g5 + or %g5, %lo(trap_block), %g5 + sub %g4, %g5, %g3 + srlx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 + + /* Increment cpu_mondo_counter[smp_processor_id()] */ + sethi %hi(cpu_mondo_counter), %g5 + or %g5, %lo(cpu_mondo_counter), %g5 + sllx %g3, 3, %g3 + add %g5, %g3, %g5 + ldx [%g5], %g3 + add %g3, 1, %g3 + stx %g3, [%g5] + /* Get CPU mondo queue base phys address into %g7. */ ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index cc97a43268ee..d883c5951e8b 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -2659,6 +2659,7 @@ void do_getpsr(struct pt_regs *regs) } } +u64 cpu_mondo_counter[NR_CPUS] = {0}; struct trap_per_cpu trap_block[NR_CPUS]; EXPORT_SYMBOL(trap_block); diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S index 395ec1800530..7d961f6e3907 100644 --- a/arch/sparc/kernel/tsb.S +++ b/arch/sparc/kernel/tsb.S @@ -375,6 +375,7 @@ tsb_flush: * %o1: TSB base config pointer * %o2: TSB huge config pointer, or NULL if none * %o3: Hypervisor TSB descriptor physical address + * %o4: Secondary context to load, if non-zero * * We have to run this whole thing with interrupts * disabled so that the current cpu doesn't change @@ -387,6 +388,17 @@ __tsb_context_switch: rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate + brz,pn %o4, 1f + mov SECONDARY_CONTEXT, %o5 + +661: stxa %o4, [%o5] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %o4, [%o5] ASI_MMU + .previous + flush %g6 + +1: TRAP_LOAD_TRAP_BLOCK(%g2, %g3) stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR] diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c index 17bd2e167e07..df707a8ad311 100644 --- a/arch/sparc/power/hibernate.c +++ b/arch/sparc/power/hibernate.c @@ -35,6 +35,5 @@ void restore_processor_state(void) { struct mm_struct *mm = current->active_mm; - load_secondary_context(mm); - tsb_context_switch(mm); + tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context)); } diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index dc1fb28d9636..489b15016303 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h @@ -78,7 +78,7 @@ struct thread_info { #ifndef __ASSEMBLY__ -void arch_release_thread_info(struct thread_info *info); +void arch_release_thread_stack(unsigned long *stack); /* How to get the thread information struct from C. */ register unsigned long stack_pointer __asm__("sp"); diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 7d5769310bef..a97ab1a69a90 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -73,8 +73,9 @@ void arch_cpu_idle(void) /* * Release a thread_info structure */ -void arch_release_thread_info(struct thread_info *info) +void arch_release_thread_stack(unsigned long *stack) { + struct thread_info *info = (void *)stack; struct single_step_state *step_state = info->step_state; if (step_state) { diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index 318b8465d302..06ceddb3a22e 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include "ctype.h" +#include "string.h" int memcmp(const void *s1, const void *s2, size_t len) { diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h index 725e820602b1..113588ddb43f 100644 --- a/arch/x86/boot/string.h +++ b/arch/x86/boot/string.h @@ -18,4 +18,13 @@ int memcmp(const void *s1, const void *s2, size_t len); #define memset(d,c,l) __builtin_memset(d,c,l) #define memcmp __builtin_memcmp +extern int strcmp(const char *str1, const char *str2); +extern int strncmp(const char *cs, const char *ct, size_t count); +extern size_t strlen(const char *s); +extern char *strstr(const char *s1, const char *s2); +extern size_t strnlen(const char *s, size_t maxlen); +extern unsigned int atou(const char *s); +extern unsigned long long simple_strtoull(const char *cp, char **endp, + unsigned int base); + #endif /* BOOT_STRING_H */ diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index cec49ecf5f31..32187f8a49b4 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -151,6 +151,8 @@ void kvm_async_pf_task_wait(u32 token) if (hlist_unhashed(&n.link)) break; + rcu_irq_exit(); + if (!n.halted) { local_irq_enable(); schedule(); @@ -159,11 +161,11 @@ void kvm_async_pf_task_wait(u32 token) /* * We cannot reschedule. So halt. */ - rcu_irq_exit(); native_safe_halt(); local_irq_disable(); - rcu_irq_enter(); } + + rcu_irq_enter(); } if (!n.halted) finish_wait(&n.wq, &wait); diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 71ebe36577c6..13598d807de0 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3522,11 +3522,13 @@ static int binder_thread_write(struct binder_proc *proc, BUG_ON(buf_node->proc != proc); w = binder_dequeue_work_head_ilocked( &buf_node->async_todo); - if (!w) + if (!w) { buf_node->has_async_transaction = 0; - else + } else { binder_enqueue_work_ilocked( - w, &thread->todo); + w, &proc->todo); + binder_wakeup_proc_ilocked(proc); + } binder_node_inner_unlock(buf_node); } trace_binder_transaction_buffer_release(buffer); @@ -3670,22 +3672,12 @@ static int binder_thread_write(struct binder_proc *proc, ref->death = death; if (ref->node->proc == NULL) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; - if (thread->looper & - (BINDER_LOOPER_STATE_REGISTERED | - BINDER_LOOPER_STATE_ENTERED)) - binder_enqueue_work( - proc, - &ref->death->work, - &thread->todo); - else { - binder_inner_proc_lock(proc); - binder_enqueue_work_ilocked( - &ref->death->work, - &proc->todo); - binder_wakeup_proc_ilocked( - proc); - binder_inner_proc_unlock(proc); - } + + binder_inner_proc_lock(proc); + binder_enqueue_work_ilocked( + &ref->death->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); } } else { if (ref->death == NULL) { @@ -3802,12 +3794,6 @@ static void binder_stat_br(struct binder_proc *proc, } } -static int binder_has_thread_work(struct binder_thread *thread) -{ - return !binder_worklist_empty(thread->proc, &thread->todo) || - thread->looper_need_return; -} - static int binder_put_node_cmd(struct binder_proc *proc, struct binder_thread *thread, void __user **ptrp, @@ -4438,12 +4424,9 @@ static unsigned int binder_poll(struct file *filp, binder_inner_proc_unlock(thread->proc); - if (binder_has_work(thread, wait_for_proc_work)) - return POLLIN; - poll_wait(filp, &thread->wait, wait); - if (binder_has_thread_work(thread)) + if (binder_has_work(thread, wait_for_proc_work)) return POLLIN; return 0; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e417e1a1d02c..5b2aee83d776 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2832,10 +2832,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) { if (!sata_pmp_attached(ap)) { - if (likely(devno < ata_link_max_devices(&ap->link))) + if (likely(devno >= 0 && + devno < ata_link_max_devices(&ap->link))) return &ap->link.device[devno]; } else { - if (likely(devno < ap->nr_pmp_links)) + if (likely(devno >= 0 && + devno < ap->nr_pmp_links)) return &ap->pmp_link[devno].device[0]; } diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6ca35495a5be..1e5cd39d0cc2 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -641,11 +641,12 @@ static int virtblk_probe(struct virtio_device *vdev) if (err) goto out_put_disk; - q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set); + q = blk_mq_init_queue(&vblk->tag_set); if (IS_ERR(q)) { err = -ENOMEM; goto out_free_tags; } + vblk->disk->queue = q; q->queuedata = vblk; diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 74777212e4cf..10038e629e6c 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -1119,6 +1119,18 @@ void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral) *diag_id = DIAG_ID_LPASS; *peripheral = PERIPHERAL_LPASS; break; + case PERIPHERAL_WCNSS: + *diag_id = 0; + *peripheral = PERIPHERAL_WCNSS; + break; + case PERIPHERAL_SENSORS: + *diag_id = 0; + *peripheral = PERIPHERAL_SENSORS; + break; + case PERIPHERAL_WDSP: + *diag_id = 0; + *peripheral = PERIPHERAL_WDSP; + break; case PERIPHERAL_CDSP: *diag_id = DIAG_ID_CDSP; *peripheral = PERIPHERAL_CDSP; diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index c70115a8c4d7..0f94bab3bf84 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -500,15 +500,29 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, temp_buf_main += (buf_len + 4); processed += buf_len; } + + if (flag_buf_1) { + fwd_info->cpd_len_1 = len_cpd; + if (fwd_info->type == TYPE_DATA) + fwd_info->upd_len_1_a = len_upd_1; + if (peripheral == PERIPHERAL_LPASS && + fwd_info->type == TYPE_DATA) + fwd_info->upd_len_2_a = len_upd_2; + } else if (flag_buf_2) { + fwd_info->cpd_len_2 = len_cpd; + if (fwd_info->type == TYPE_DATA) + fwd_info->upd_len_1_b = len_upd_1; + if (peripheral == PERIPHERAL_LPASS && + fwd_info->type == TYPE_DATA) + fwd_info->upd_len_2_b = len_upd_2; + } + if (peripheral == PERIPHERAL_LPASS && fwd_info->type == TYPE_DATA && len_upd_2) { - if (flag_buf_1) { - fwd_info->upd_len_2_a = len_upd_2; + if (flag_buf_1) temp_ptr_upd = fwd_info->buf_upd_2_a; - } else { - fwd_info->upd_len_2_b = len_upd_2; + else temp_ptr_upd = fwd_info->buf_upd_2_b; - } temp_ptr_upd->ctxt &= 0x00FFFFFF; temp_ptr_upd->ctxt |= (SET_PD_CTXT(ctxt_upd_2)); @@ -522,15 +536,10 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, fwd_info->upd_len_2_b = 0; } if (fwd_info->type == TYPE_DATA && len_upd_1) { - if (flag_buf_1) { - fwd_info->upd_len_1_a = - len_upd_1; + if (flag_buf_1) temp_ptr_upd = fwd_info->buf_upd_1_a; - } else { - fwd_info->upd_len_1_b = - len_upd_1; + else temp_ptr_upd = fwd_info->buf_upd_1_b; - } temp_ptr_upd->ctxt &= 0x00FFFFFF; temp_ptr_upd->ctxt |= (SET_PD_CTXT(ctxt_upd_1)); @@ -544,10 +553,6 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, fwd_info->upd_len_1_b = 0; } if (len_cpd) { - if (flag_buf_1) - fwd_info->cpd_len_1 = len_cpd; - else - fwd_info->cpd_len_2 = len_cpd; temp_ptr_cpd->ctxt &= 0x00FFFFFF; temp_ptr_cpd->ctxt |= (SET_PD_CTXT(ctxt_cpd)); @@ -1332,12 +1337,33 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt) if (ctxt == 1 && fwd_info->buf_1) { /* Buffer 1 for core PD is freed */ - atomic_set(&fwd_info->buf_1->in_busy, 0); fwd_info->cpd_len_1 = 0; + + if (peripheral == PERIPHERAL_LPASS) { + if (!fwd_info->upd_len_1_a && + !fwd_info->upd_len_2_a) + atomic_set(&fwd_info->buf_1->in_busy, 0); + } else if (peripheral == PERIPHERAL_MODEM) { + if (!fwd_info->upd_len_1_a) + atomic_set(&fwd_info->buf_1->in_busy, 0); + } else { + atomic_set(&fwd_info->buf_1->in_busy, 0); + } } else if (ctxt == 2 && fwd_info->buf_2) { /* Buffer 2 for core PD is freed */ - atomic_set(&fwd_info->buf_2->in_busy, 0); fwd_info->cpd_len_2 = 0; + + if (peripheral == PERIPHERAL_LPASS) { + if (!fwd_info->upd_len_1_b && + !fwd_info->upd_len_2_b) + atomic_set(&fwd_info->buf_2->in_busy, 0); + } else if (peripheral == PERIPHERAL_MODEM) { + if (!fwd_info->upd_len_1_b) + atomic_set(&fwd_info->buf_2->in_busy, 0); + } else { + atomic_set(&fwd_info->buf_2->in_busy, 0); + } + } else if (ctxt == 3 && fwd_info->buf_upd_1_a) { /* Buffer 1 for user pd 1 is freed */ atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 1a563ea5f50c..ed9a6ea37397 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -27,11 +27,11 @@ /** * Max hardware block in certain hardware. For ex: sspp pipes - * can have QSEED, pcc, igc, pa, csc, etc. This count is max - * 12 based on software design. It should be increased if any of the + * can have QSEED, pcc, igc, pa, csc, qos entries, etc. This count is + * 64 based on software design. It should be increased if any of the * hardware block has more subblocks. */ -#define MAX_SDE_HW_BLK 12 +#define MAX_SDE_HW_BLK 64 /* each entry will have register address and bit offset in that register */ #define MAX_BIT_OFFSET 2 @@ -444,8 +444,16 @@ static uint32_t _sde_copy_formats( static int _parse_dt_u32_handler(struct device_node *np, char *prop_name, u32 *offsets, int len, bool mandatory) { - int rc = of_property_read_u32_array(np, prop_name, offsets, len); + int rc = -EINVAL; + if (len > MAX_SDE_HW_BLK) { + SDE_ERROR( + "prop: %s tries out of bound access for u32 array read len: %d\n", + prop_name, len); + return -E2BIG; + } + + rc = of_property_read_u32_array(np, prop_name, offsets, len); if (rc && mandatory) SDE_ERROR("mandatory prop: %s u32 array read len:%d\n", prop_name, len); @@ -467,6 +475,14 @@ static int _parse_dt_bit_offset(struct device_node *np, if (arr) { len /= sizeof(u32); len &= ~0x1; + + if (len > (MAX_SDE_HW_BLK * MAX_BIT_OFFSET)) { + SDE_ERROR( + "prop: %s len: %d will lead to out of bound access\n", + prop_name, len / MAX_BIT_OFFSET); + return -E2BIG; + } + for (i = 0, j = 0; i < len; j++) { PROP_BITVALUE_ACCESS(prop_value, prop_index, j, 0) = be32_to_cpu(arr[i]); @@ -501,8 +517,8 @@ static int _validate_dt_entry(struct device_node *np, sde_prop[0].prop_name); if ((*off_count > MAX_BLOCKS) || (*off_count < 0)) { if (sde_prop[0].is_mandatory) { - SDE_ERROR("invalid hw offset prop name:%s\"\ - count: %d\n", + SDE_ERROR( + "invalid hw offset prop name:%s count: %d\n", sde_prop[0].prop_name, *off_count); rc = -EINVAL; } @@ -545,8 +561,9 @@ static int _validate_dt_entry(struct device_node *np, sde_prop[i].type); break; } - SDE_DEBUG("prop id:%d prop name:%s prop type:%d \"\ - prop_count:%d\n", i, sde_prop[i].prop_name, + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d prop_count:%d\n", + i, sde_prop[i].prop_name, sde_prop[i].type, prop_count[i]); if (rc && sde_prop[i].is_mandatory && @@ -564,14 +581,16 @@ static int _validate_dt_entry(struct device_node *np, if (off_count && (prop_count[i] != *off_count) && sde_prop[i].is_mandatory) { - SDE_ERROR("prop:%s count:%d is different compared to \"\ - offset array:%d\n", sde_prop[i].prop_name, + SDE_ERROR( + "prop:%s count:%d is different compared to offset array:%d\n", + sde_prop[i].prop_name, prop_count[i], *off_count); rc = -EINVAL; goto end; } else if (off_count && prop_count[i] != *off_count) { - SDE_DEBUG("prop:%s count:%d is different compared to \"\ - offset array:%d\n", sde_prop[i].prop_name, + SDE_DEBUG( + "prop:%s count:%d is different compared to offset array:%d\n", + sde_prop[i].prop_name, prop_count[i], *off_count); rc = 0; prop_count[i] = 0; @@ -607,8 +626,9 @@ static int _read_dt_entry(struct device_node *np, case PROP_TYPE_U32: rc = of_property_read_u32(np, sde_prop[i].prop_name, &PROP_VALUE_ACCESS(prop_value, i, 0)); - SDE_DEBUG("prop id:%d prop name:%s prop type:%d \"\ - value:0x%x\n", i, sde_prop[i].prop_name, + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d value:0x%x\n", + i, sde_prop[i].prop_name, sde_prop[i].type, PROP_VALUE_ACCESS(prop_value, i, 0)); if (rc) @@ -618,8 +638,9 @@ static int _read_dt_entry(struct device_node *np, PROP_VALUE_ACCESS(prop_value, i, 0) = of_property_read_bool(np, sde_prop[i].prop_name); - SDE_DEBUG("prop id:%d prop name:%s prop type:%d \"\ - value:0x%x\n", i, sde_prop[i].prop_name, + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d value:0x%x\n", + i, sde_prop[i].prop_name, sde_prop[i].type, PROP_VALUE_ACCESS(prop_value, i, 0)); break; @@ -628,8 +649,9 @@ static int _read_dt_entry(struct device_node *np, &PROP_VALUE_ACCESS(prop_value, i, 0), prop_count[i], sde_prop[i].is_mandatory); if (rc && sde_prop[i].is_mandatory) { - SDE_ERROR("%s prop validation success but \"\ - read failed\n", sde_prop[i].prop_name); + SDE_ERROR( + "%s prop validation success but read failed\n", + sde_prop[i].prop_name); prop_exists[i] = false; goto end; } else { @@ -651,19 +673,21 @@ static int _read_dt_entry(struct device_node *np, prop_value, i, prop_count[i], sde_prop[i].is_mandatory); if (rc && sde_prop[i].is_mandatory) { - SDE_ERROR("%s prop validation success but \"\ - read failed\n", sde_prop[i].prop_name); + SDE_ERROR( + "%s prop validation success but read failed\n", + sde_prop[i].prop_name); prop_exists[i] = false; goto end; } else { if (rc) prop_exists[i] = false; - SDE_DEBUG("prop id:%d prop name:%s prop \"\ - type:%d", i, sde_prop[i].prop_name, + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d", + i, sde_prop[i].prop_name, sde_prop[i].type); for (j = 0; j < prop_count[i]; j++) - SDE_DEBUG(" count[%d]: bit:0x%x \"\ - off:0x%x \n", j, + SDE_DEBUG( + "count[%d]: bit:0x%x off:0x%x\n", j, PROP_BITVALUE_ACCESS(prop_value, i, j, 0), PROP_BITVALUE_ACCESS(prop_value, @@ -984,6 +1008,13 @@ static int sde_sspp_parse_dt(struct device_node *np, snprintf(sblk->src_blk.name, SDE_HW_BLK_NAME_LEN, "sspp_src_%u", sspp->id - SSPP_VIG0); + if (sspp->clk_ctrl >= SDE_CLK_CTRL_MAX) { + SDE_ERROR("%s: invalid clk ctrl: %d\n", + sblk->src_blk.name, sspp->clk_ctrl); + rc = -EINVAL; + goto end; + } + sblk->maxhdeciexp = MAX_HORZ_DECIMATION; sblk->maxvdeciexp = MAX_VERT_DECIMATION; @@ -1345,6 +1376,14 @@ static int sde_wb_parse_dt(struct device_node *np, PROP_VALUE_ACCESS(prop_value, WB_ID, i); wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i); wb->vbif_idx = VBIF_NRT; + + if (wb->clk_ctrl >= SDE_CLK_CTRL_MAX) { + SDE_ERROR("%s: invalid clk ctrl: %d\n", + wb->name, wb->clk_ctrl); + rc = -EINVAL; + goto end; + } + wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0); wb->format_list = wb2_formats; if (!prop_exists[WB_LEN]) @@ -2067,7 +2106,7 @@ static int sde_perf_parse_dt(struct device_node *np, goto end; } - prop_value = kzalloc(SDE_PROP_MAX * + prop_value = kzalloc(PERF_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c index b87bc75f17ea..5a0c5e677ed8 100644 --- a/drivers/gpu/drm/msm/sde_dbg.c +++ b/drivers/gpu/drm/msm/sde_dbg.c @@ -1765,7 +1765,7 @@ static ssize_t sde_dbg_reg_base_offset_write(struct file *file, buf[count] = 0; /* end of string */ - if (sscanf(buf, "%5x %x", &off, &cnt) != 2) + if (sscanf(buf, "%x %x", &off, &cnt) != 2) return -EFAULT; if (off > dbg->max_offset) @@ -1884,7 +1884,7 @@ static ssize_t sde_dbg_reg_base_reg_read(struct file *file, } if (!dbg->buf) { - char *hwbuf, *hwbuf_cur; + char *hwbuf; char dump_buf[64]; char __iomem *ioptr; int cnt, tot; @@ -1900,39 +1900,36 @@ static ssize_t sde_dbg_reg_base_reg_read(struct file *file, if (!dbg->buf) return -ENOMEM; - hwbuf = kzalloc(dbg->buf_len, GFP_KERNEL); + hwbuf = kzalloc(ROW_BYTES, GFP_KERNEL); if (!hwbuf) { kfree(dbg->buf); return -ENOMEM; } - hwbuf_cur = hwbuf; ioptr = dbg->base + dbg->off; tot = 0; - _sde_dbg_enable_power(true); - memcpy_fromio(hwbuf, ioptr, dbg->buf_len); - - _sde_dbg_enable_power(false); - for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) { - hex_dump_to_buffer(hwbuf_cur, + memcpy_fromio(hwbuf, ioptr, ROW_BYTES); + hex_dump_to_buffer(hwbuf, min(cnt, ROW_BYTES), ROW_BYTES, GROUP_BYTES, dump_buf, sizeof(dump_buf), false); len = scnprintf(dbg->buf + tot, dbg->buf_len - tot, "0x%08x: %s\n", - ((int) (unsigned long) hwbuf_cur) - + ((int) (unsigned long) ioptr) - ((int) (unsigned long) dbg->base), dump_buf); - hwbuf_cur += ROW_BYTES; + ioptr += ROW_BYTES; tot += len; if (tot >= dbg->buf_len) break; } + _sde_dbg_enable_power(false); + dbg->buf_len = tot; kfree(hwbuf); } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index bf4674aa6405..bb9cd35d7fdf 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -296,7 +296,7 @@ static int rcar_du_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(rcdu->mmio)) - ret = PTR_ERR(rcdu->mmio); + return PTR_ERR(rcdu->mmio); /* DRM/KMS objects */ ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index 6a81e084593b..2b59d80a09b8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -338,7 +338,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, info->fbops = &virtio_gpufb_ops; info->pixmap.flags = FB_PIXMAP_SYSTEM; - info->screen_base = obj->vmap; + info->screen_buffer = obj->vmap; info->screen_size = obj->gem_base.size; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &vfbdev->helper, diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 7cab049771de..c620c7ac1afa 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -807,13 +807,13 @@ static int adreno_of_get_pwrlevels(struct adreno_device *adreno_dev, struct device_node *parent) { struct device_node *node, *child; + unsigned int bin = 0; node = of_find_node_by_name(parent, "qcom,gpu-pwrlevel-bins"); if (node == NULL) return adreno_of_get_legacy_pwrlevels(adreno_dev, parent); for_each_child_of_node(node, child) { - unsigned int bin; if (of_property_read_u32(child, "qcom,speed-bin", &bin)) continue; @@ -829,6 +829,8 @@ static int adreno_of_get_pwrlevels(struct adreno_device *adreno_dev, } } + KGSL_CORE_ERR("GPU speed_bin:%d mismatch for efused bin:%d\n", + adreno_dev->speed_bin, bin); return -ENODEV; } @@ -1161,6 +1163,10 @@ static int adreno_init(struct kgsl_device *device) struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); int ret; + if (!adreno_is_a3xx(adreno_dev)) + kgsl_sharedmem_set(device, &device->scratch, 0, 0, + device->scratch.size); + ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); if (ret) return ret; diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index ddc53edce3c1..65e73356857f 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -203,8 +203,9 @@ int adreno_ringbuffer_start(struct adreno_device *adreno_dev, FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { kgsl_sharedmem_set(device, &(rb->buffer_desc), 0, 0xAA, KGSL_RB_SIZE); - kgsl_sharedmem_writel(device, &device->scratch, - SCRATCH_RPTR_OFFSET(rb->id), 0); + if (!adreno_is_a3xx(adreno_dev)) + kgsl_sharedmem_writel(device, &device->scratch, + SCRATCH_RPTR_OFFSET(rb->id), 0); rb->wptr = 0; rb->_wptr = 0; rb->wptr_preempt_end = 0xFFFFFFFF; @@ -265,9 +266,16 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) { - int status = 0; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - int i; + int i, status; + + if (!adreno_is_a3xx(adreno_dev)) { + status = kgsl_allocate_global(device, &device->scratch, + PAGE_SIZE, 0, 0, "scratch"); + if (status != 0) + return status; + } if (nopreempt == false && ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) adreno_dev->num_ringbuffers = gpudev->num_prio_levels; @@ -303,9 +311,13 @@ static void _adreno_ringbuffer_close(struct adreno_device *adreno_dev, void adreno_ringbuffer_close(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_ringbuffer *rb; int i; + if (!adreno_is_a3xx(adreno_dev)) + kgsl_free_global(device, &device->scratch); + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) _adreno_ringbuffer_close(adreno_dev, rb); } @@ -489,12 +501,17 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP) total_sizedwords += 9; - /* WAIT_MEM_WRITES - needed in the stall on fault case - * to prevent out of order CP operations that can result - * in a CACHE_FLUSH_TS interrupt storm */ - if (test_bit(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE, + /* Don't insert any commands if stall on fault is not supported. */ + if ((ADRENO_GPUREV(adreno_dev) > 500) && !adreno_is_a510(adreno_dev)) { + /* + * WAIT_MEM_WRITES - needed in the stall on fault case + * to prevent out of order CP operations that can result + * in a CACHE_FLUSH_TS interrupt storm + */ + if (test_bit(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE, &adreno_dev->ft_pf_policy)) - total_sizedwords += 1; + total_sizedwords += 1; + } ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords); if (IS_ERR(ringcmds)) @@ -581,14 +598,18 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (profile_ready) adreno_profile_postib_processing(adreno_dev, &flags, &ringcmds); - /* - * WAIT_MEM_WRITES - needed in the stall on fault case to prevent - * out of order CP operations that can result in a CACHE_FLUSH_TS - * interrupt storm - */ - if (test_bit(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE, + /* Don't insert any commands if stall on fault is not supported. */ + if ((ADRENO_GPUREV(adreno_dev) > 500) && !adreno_is_a510(adreno_dev)) { + /* + * WAIT_MEM_WRITES - needed in the stall on fault case + * to prevent out of order CP operations that can result + * in a CACHE_FLUSH_TS interrupt storm + */ + if (test_bit(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE, &adreno_dev->ft_pf_policy)) - *ringcmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 0); + *ringcmds++ = cp_packet(adreno_dev, + CP_WAIT_MEM_WRITES, 0); + } /* * Do a unique memory write from the GPU. This can be used in diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index afb489f10172..bbdc598d057d 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1120,8 +1120,6 @@ static int kgsl_open_device(struct kgsl_device *device) atomic_inc(&device->active_cnt); kgsl_sharedmem_set(device, &device->memstore, 0, 0, device->memstore.size); - kgsl_sharedmem_set(device, &device->scratch, 0, 0, - device->scratch.size); result = device->ftbl->init(device); if (result) @@ -4399,13 +4397,13 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr, if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) { val = get_unmapped_area(NULL, addr, len, 0, flags); if (IS_ERR_VALUE(val)) - KGSL_MEM_ERR(device, + KGSL_DRV_ERR_RATELIMIT(device, "get_unmapped_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n", private->pid, addr, pgoff, len, (int) val); } else { val = _get_svm_area(private, entry, addr, len, flags); if (IS_ERR_VALUE(val)) - KGSL_MEM_ERR(device, + KGSL_DRV_ERR_RATELIMIT(device, "_get_svm_area: pid %d mmap_base %lx addr %lx pgoff %lx len %ld failed error %d\n", private->pid, current->mm->mmap_base, addr, pgoff, len, (int) val); @@ -4724,11 +4722,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device) if (status != 0) goto error_close_mmu; - status = kgsl_allocate_global(device, &device->scratch, - PAGE_SIZE, 0, 0, "scratch"); - if (status != 0) - goto error_free_memstore; - /* * The default request type PM_QOS_REQ_ALL_CORES is * applicable to all CPU cores that are online and @@ -4774,8 +4767,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device) return 0; -error_free_memstore: - kgsl_free_global(device, &device->memstore); error_close_mmu: kgsl_mmu_close(device); error_pwrctrl_close: @@ -4803,8 +4794,6 @@ void kgsl_device_platform_remove(struct kgsl_device *device) idr_destroy(&device->context_idr); - kgsl_free_global(device, &device->scratch); - kgsl_free_global(device, &device->memstore); kgsl_mmu_close(device); diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h index 51baabefb6d3..9b7833bdb2df 100644 --- a/drivers/gpu/msm/kgsl_log.h +++ b/drivers/gpu/msm/kgsl_log.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2011,2013-2014,2016 The Linux Foundation. +/* Copyright (c) 2002,2008-2011,2013-2014,2016-2017 The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -67,6 +67,13 @@ __func__, ##args);\ } while (0) +#define KGSL_LOG_ERR_RATELIMITED(dev, lvl, fmt, args...) \ + do { \ + if ((lvl) >= 3) \ + dev_err_ratelimited(dev, "|%s| " fmt, \ + __func__, ##args);\ + } while (0) + #define KGSL_DRV_INFO(_dev, fmt, args...) \ KGSL_LOG_INFO(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_WARN(_dev, fmt, args...) \ @@ -77,6 +84,8 @@ KGSL_LOG_ERR(_dev->dev, _dev->drv_log, fmt, ##args) KGSL_LOG_CRIT(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_CRIT_RATELIMIT(_dev, fmt, args...) \ KGSL_LOG_CRIT_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args) +#define KGSL_DRV_ERR_RATELIMIT(_dev, fmt, args...) \ +KGSL_LOG_ERR_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_FATAL(_dev, fmt, args...) \ KGSL_LOG_FATAL((_dev)->dev, (_dev)->drv_log, fmt, ##args) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index b0edb66a291b..0b7f5a701c60 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -1581,7 +1581,7 @@ isert_rcv_completion(struct iser_rx_desc *desc, struct isert_conn *isert_conn, u32 xfer_len) { - struct ib_device *ib_dev = isert_conn->cm_id->device; + struct ib_device *ib_dev = isert_conn->device->ib_device; struct iscsi_hdr *hdr; u64 rx_dma; int rx_buflen; diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c index a5ea27ad0e16..fdcc14653b64 100644 --- a/drivers/input/misc/keychord.c +++ b/drivers/input/misc/keychord.c @@ -60,6 +60,10 @@ struct keychord_device { unsigned char head; unsigned char tail; __u16 buff[BUFFER_SIZE]; + /* Bit to serialize writes to this device */ +#define KEYCHORD_BUSY 0x01 + unsigned long flags; + wait_queue_head_t write_waitq; }; static int check_keychord(struct keychord_device *kdev, @@ -172,7 +176,6 @@ static int keychord_connect(struct input_handler *handler, goto err_input_open_device; pr_info("keychord: using input dev %s for fevent\n", dev->name); - return 0; err_input_open_device: @@ -225,6 +228,41 @@ static ssize_t keychord_read(struct file *file, char __user *buffer, } /* + * serializes writes on a device. can use mutex_lock_interruptible() + * for this particular use case as well - a matter of preference. + */ +static int +keychord_write_lock(struct keychord_device *kdev) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&kdev->lock, flags); + while (kdev->flags & KEYCHORD_BUSY) { + spin_unlock_irqrestore(&kdev->lock, flags); + ret = wait_event_interruptible(kdev->write_waitq, + ((kdev->flags & KEYCHORD_BUSY) == 0)); + if (ret) + return ret; + spin_lock_irqsave(&kdev->lock, flags); + } + kdev->flags |= KEYCHORD_BUSY; + spin_unlock_irqrestore(&kdev->lock, flags); + return 0; +} + +static void +keychord_write_unlock(struct keychord_device *kdev) +{ + unsigned long flags; + + spin_lock_irqsave(&kdev->lock, flags); + kdev->flags &= ~KEYCHORD_BUSY; + spin_unlock_irqrestore(&kdev->lock, flags); + wake_up_interruptible(&kdev->write_waitq); +} + +/* * keychord_write is used to configure the driver */ static ssize_t keychord_write(struct file *file, const char __user *buffer, @@ -232,9 +270,11 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, { struct keychord_device *kdev = file->private_data; struct input_keychord *keychords = 0; - struct input_keychord *keychord, *next, *end; + struct input_keychord *keychord; int ret, i, key; unsigned long flags; + size_t resid = count; + size_t key_bytes; if (count < sizeof(struct input_keychord)) return -EINVAL; @@ -248,6 +288,22 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, return -EFAULT; } + /* + * Serialize writes to this device to prevent various races. + * 1) writers racing here could do duplicate input_unregister_handler() + * calls, resulting in attempting to unlink a node from a list that + * does not exist. + * 2) writers racing here could do duplicate input_register_handler() calls + * below, resulting in a duplicate insertion of a node into the list. + * 3) a double kfree of keychords can occur (in the event that + * input_register_handler() fails below. + */ + ret = keychord_write_lock(kdev); + if (ret) { + kfree(keychords); + return ret; + } + /* unregister handler before changing configuration */ if (kdev->registered) { input_unregister_handler(&kdev->input_handler); @@ -265,15 +321,29 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, kdev->head = kdev->tail = 0; keychord = keychords; - end = (struct input_keychord *)((char *)keychord + count); - while (keychord < end) { - next = NEXT_KEYCHORD(keychord); - if (keychord->count <= 0 || next > end) { + while (resid > 0) { + /* Is the entire keychord entry header present ? */ + if (resid < sizeof(struct input_keychord)) { + pr_err("keychord: Insufficient bytes present for header %zu\n", + resid); + goto err_unlock_return; + } + resid -= sizeof(struct input_keychord); + if (keychord->count <= 0) { pr_err("keychord: invalid keycode count %d\n", keychord->count); goto err_unlock_return; } + key_bytes = keychord->count * sizeof(keychord->keycodes[0]); + /* Do we have all the expected keycodes ? */ + if (resid < key_bytes) { + pr_err("keychord: Insufficient bytes present for keycount %zu\n", + resid); + goto err_unlock_return; + } + resid -= key_bytes; + if (keychord->version != KEYCHORD_VERSION) { pr_err("keychord: unsupported version %d\n", keychord->version); @@ -292,7 +362,7 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, } kdev->keychord_count++; - keychord = next; + keychord = NEXT_KEYCHORD(keychord); } kdev->keychords = keychords; @@ -302,15 +372,19 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, if (ret) { kfree(keychords); kdev->keychords = 0; + keychord_write_unlock(kdev); return ret; } kdev->registered = 1; + keychord_write_unlock(kdev); + return count; err_unlock_return: spin_unlock_irqrestore(&kdev->lock, flags); kfree(keychords); + keychord_write_unlock(kdev); return -EINVAL; } @@ -336,6 +410,7 @@ static int keychord_open(struct inode *inode, struct file *file) spin_lock_init(&kdev->lock); init_waitqueue_head(&kdev->waitq); + init_waitqueue_head(&kdev->write_waitq); kdev->input_handler.event = keychord_event; kdev->input_handler.connect = keychord_connect; @@ -357,6 +432,7 @@ static int keychord_release(struct inode *inode, struct file *file) if (kdev->registered) input_unregister_handler(&kdev->input_handler); + kfree(kdev->keychords); kfree(kdev); return 0; diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c index a18fe5d47238..b4857cd7069e 100644 --- a/drivers/media/pci/saa7164/saa7164-bus.c +++ b/drivers/media/pci/saa7164/saa7164-bus.c @@ -393,11 +393,11 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size); msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command); msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector); + memcpy(msg, &msg_tmp, sizeof(*msg)); /* No need to update the read positions, because this was a peek */ /* If the caller specifically want to peek, return */ if (peekonly) { - memcpy(msg, &msg_tmp, sizeof(*msg)); goto peekout; } @@ -442,21 +442,15 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, space_rem = bus->m_dwSizeGetRing - curr_grp; if (space_rem < sizeof(*msg)) { - /* msg wraps around the ring */ - memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem); - memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing, - sizeof(*msg) - space_rem); if (buf) memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) - space_rem, buf_size); } else if (space_rem == sizeof(*msg)) { - memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); if (buf) memcpy_fromio(buf, bus->m_pdwGetRing, buf_size); } else { /* Additional data wraps around the ring */ - memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); if (buf) { memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), space_rem - sizeof(*msg)); @@ -469,15 +463,10 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, } else { /* No wrapping */ - memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); if (buf) memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), buf_size); } - /* Convert from little endian to CPU */ - msg->size = le16_to_cpu((__force __le16)msg->size); - msg->command = le32_to_cpu((__force __le32)msg->command); - msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector); /* Update the read positions, adjusting the ring */ saa7164_writel(bus->m_dwGetReadPos, new_grp); diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 7767e072d623..1f656a3a84b9 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1709,27 +1709,9 @@ static long vpfe_param_handler(struct file *file, void *priv, switch (cmd) { case VPFE_CMD_S_CCDC_RAW_PARAMS: + ret = -EINVAL; v4l2_warn(&vpfe_dev->v4l2_dev, - "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); - if (ccdc_dev->hw_ops.set_params) { - ret = ccdc_dev->hw_ops.set_params(param); - if (ret) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "Error setting parameters in CCDC\n"); - goto unlock_out; - } - ret = vpfe_get_ccdc_image_format(vpfe_dev, - &vpfe_dev->fmt); - if (ret < 0) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "Invalid image format at CCDC\n"); - goto unlock_out; - } - } else { - ret = -EINVAL; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n"); - } + "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n"); break; default: ret = -ENOTTY; diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index d33dc758aef9..04e879fc3bcf 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -699,6 +699,12 @@ void msm_vfe47_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { + if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { + pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); + spin_unlock_irqrestore(&vfe_dev->reg_update_lock, + flags); + return; + } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res-> vfe_base[ISP_VFE0] + 0x4AC); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index 23f936258660..22eb86f4f875 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -53,7 +53,6 @@ MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); #define MAX_OVERFLOW_COUNTERS 29 #define OVERFLOW_LENGTH 1024 #define OVERFLOW_BUFFER_LENGTH 64 -static char stat_line[OVERFLOW_LENGTH]; struct msm_isp_statistics stats; struct msm_isp_ub_info ub_info; @@ -113,19 +112,30 @@ static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file) return 0; } -static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char, - size_t t_size_t, loff_t *t_loff_t) +static ssize_t vfe_debugfs_statistics_read(struct file *t_file, + char __user *t_char, size_t t_size_t, loff_t *t_loff_t) { int i; + size_t rc; uint64_t *ptr; char buffer[OVERFLOW_BUFFER_LENGTH] = {0}; + char *stat_line; struct vfe_device *vfe_dev = (struct vfe_device *) t_file->private_data; - struct msm_isp_statistics *stats = vfe_dev->stats; + struct msm_isp_statistics *stats; - memset(stat_line, 0, sizeof(stat_line)); + stat_line = kzalloc(OVERFLOW_LENGTH, GFP_KERNEL); + if (!stat_line) + return -ENOMEM; + spin_lock(&vfe_dev->common_data->common_dev_data_lock); + stats = vfe_dev->stats; msm_isp_util_get_bandwidth_stats(vfe_dev, stats); + spin_unlock(&vfe_dev->common_data->common_dev_data_lock); ptr = (uint64_t *)(stats); + if (MAX_OVERFLOW_COUNTERS > OVERFLOW_LENGTH) { + kfree(stat_line); + return -EINVAL; + } for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) { strlcat(stat_line, stats_str[i], sizeof(stat_line)); strlcat(stat_line, " ", sizeof(stat_line)); @@ -133,8 +143,10 @@ static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char, strlcat(stat_line, buffer, sizeof(stat_line)); strlcat(stat_line, "\r\n", sizeof(stat_line)); } - return simple_read_from_buffer(t_char, t_size_t, + rc = simple_read_from_buffer(t_char, t_size_t, t_loff_t, stat_line, strlen(stat_line)); + kfree(stat_line); + return rc; } static ssize_t vfe_debugfs_statistics_write(struct file *t_file, @@ -142,8 +154,12 @@ static ssize_t vfe_debugfs_statistics_write(struct file *t_file, { struct vfe_device *vfe_dev = (struct vfe_device *) t_file->private_data; - struct msm_isp_statistics *stats = vfe_dev->stats; + struct msm_isp_statistics *stats; + + spin_lock(&vfe_dev->common_data->common_dev_data_lock); + stats = vfe_dev->stats; memset(stats, 0, sizeof(struct msm_isp_statistics)); + spin_unlock(&vfe_dev->common_data->common_dev_data_lock); return sizeof(struct msm_isp_statistics); } diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 7cfeffc92d48..194a6583103e 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -746,6 +746,16 @@ static long msm_private_ioctl(struct file *file, void *fh, if (!event_data) return -EINVAL; + switch (cmd) { + case MSM_CAM_V4L2_IOCTL_NOTIFY: + case MSM_CAM_V4L2_IOCTL_CMD_ACK: + case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG: + case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR: + break; + default: + return -ENOTTY; + } + memset(&event, 0, sizeof(struct v4l2_event)); session_id = event_data->session_id; stream_id = event_data->stream_id; diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index 223ddf39dce8..c77367ed1603 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -1213,6 +1213,9 @@ static long msm_flash_subdev_do_ioctl( break; } break; + case VIDIOC_MSM_FLASH_CFG: + pr_err("invalid cmd 0x%x received\n", cmd); + return -EINVAL; default: return msm_flash_subdev_ioctl(sd, cmd, arg); } diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c index 2d2296893140..9f3e2cc3a72f 100644 --- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c @@ -523,13 +523,17 @@ static ssize_t mpq_sdmx_log_level_write(struct file *fp, int level; struct mpq_demux *mpq_demux = fp->private_data; - if (count >= 16) + if (count == 0 || count >= 16) return -EINVAL; - ret_count = simple_write_to_buffer(user_str, 16, position, user_buffer, + memset(user_str, '\0', sizeof(user_str)); + + ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer, count); if (ret_count < 0) return ret_count; + else if (ret_count == 0) + return -EINVAL; ret = kstrtoint(user_str, 0, &level); if (ret) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index abf20aef1256..422c7a590a45 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -2003,8 +2003,10 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr, sde_rot_mgr_unlock(mgr); for (i = req->count - 1; i >= 0; i--) { entry = req->entries + i; - flush_kthread_worker(&entry->commitq->rot_kw); - flush_kthread_worker(&entry->doneq->rot_kw); + if (entry->commitq) + flush_kthread_worker(&entry->commitq->rot_kw); + if (entry->doneq) + flush_kthread_worker(&entry->doneq->rot_kw); } sde_rot_mgr_lock(mgr); SDEROT_DBG("cancel work done\n"); diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 3677bb6e32e6..2eaae18bc2e9 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1425,10 +1425,6 @@ void *msm_vidc_open(int core_id, int session_type) setup_event_queue(inst, &core->vdev[session_type].vdev); - mutex_lock(&core->lock); - list_add_tail(&inst->list, &core->instances); - mutex_unlock(&core->lock); - rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE); if (rc) { dprintk(VIDC_ERR, @@ -1442,15 +1438,15 @@ void *msm_vidc_open(int core_id, int session_type) goto fail_init; } + mutex_lock(&core->lock); + list_add_tail(&inst->list, &core->instances); + mutex_unlock(&core->lock); + inst->debugfs_root = msm_vidc_debugfs_init_inst(inst, core->debugfs_root); return inst; fail_init: - mutex_lock(&core->lock); - list_del(&inst->list); - mutex_unlock(&core->lock); - v4l2_fh_del(&inst->event_handler); v4l2_fh_exit(&inst->event_handler); vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index a32659fcd266..efc21b1da211 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -254,7 +254,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return 0; case LIRC_GET_REC_RESOLUTION: - val = dev->rx_resolution; + val = dev->rx_resolution / 1000; break; case LIRC_SET_WIDEBAND_RECEIVER: diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 311f6d639d06..548a9e8b72ae 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -401,6 +401,7 @@ int mmc_add_card(struct mmc_card *card) return ret; mmc_card_set_present(card); + device_enable_async_suspend(&card->dev); return 0; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 5033107f6e26..9bef77ba29fd 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1286,6 +1286,7 @@ static int _mmc_sd_resume(struct mmc_host *host) if (err) { pr_err("%s: %s: mmc_sd_init_card_failed (%d)\n", mmc_hostname(host), __func__, err); + mmc_power_off(host); goto out; } mmc_card_clr_suspended(host->card); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index ab4837128cb2..c86a800fc203 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -5015,7 +5015,7 @@ static int sdhci_msm_suspend_noirq(struct device *dev) } static const struct dev_pm_ops sdhci_msm_pmops = { - SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume) SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume, NULL) .suspend_noirq = sdhci_msm_suspend_noirq, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0033fea0a800..5906bba0aeff 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3041,11 +3041,6 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) * above in sdhci_cmd_irq(). */ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { - if (intmask & SDHCI_INT_DATA_TIMEOUT) { - host->cmd->error = -ETIMEDOUT; - tasklet_schedule(&host->finish_tasklet); - return; - } if (intmask & SDHCI_INT_DATA_END) { /* * Some cards handle busy-end interrupt @@ -3059,8 +3054,20 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) return; } if (host->quirks2 & - SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD) + SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD) { + pr_err_ratelimited("%s: %s: ignoring interrupt: 0x%08x due to DATATOUT_FOR_R1B quirk\n", + mmc_hostname(host->mmc), + __func__, intmask); + MMC_TRACE(host->mmc, + "%s: Quirk ignoring intr: 0x%08x\n", + __func__, intmask); return; + } + if (intmask & SDHCI_INT_DATA_TIMEOUT) { + host->cmd->error = -ETIMEDOUT; + tasklet_schedule(&host->finish_tasklet); + return; + } } pr_err("%s: Got data interrupt 0x%08x even " diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig index a8001b41c81c..5b315573387e 100644 --- a/drivers/net/can/spi/Kconfig +++ b/drivers/net/can/spi/Kconfig @@ -12,4 +12,10 @@ config CAN_RH850 depends on HAS_DMA ---help--- Driver for the Renesas RH850 SPI CAN controller. + +config CAN_K61 + tristate "Freescale K61 SPI CAN controllers" + depends on SPI + ---help--- + Driver for the Freescale K61 SPI CAN controllers. endmenu diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile index e84da9b8d5ab..375a6cbfbb67 100644 --- a/drivers/net/can/spi/Makefile +++ b/drivers/net/can/spi/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_RH850) += rh850.o +obj-${CONFIG_CAN_K61} += k61.o diff --git a/drivers/net/can/spi/k61.c b/drivers/net/can/spi/k61.c new file mode 100644 index 000000000000..9ce0ad854caa --- /dev/null +++ b/drivers/net/can/spi/k61.c @@ -0,0 +1,936 @@ +/* Copyright (c) 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 + * 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 <linux/interrupt.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/workqueue.h> +#include <linux/spi/spi.h> +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/uaccess.h> + +#define DEBUG_K61 0 +#if DEBUG_K61 == 1 +#define LOGDI(...) dev_info(&priv_data->spidev->dev, __VA_ARGS__) +#define LOGNI(...) netdev_info(netdev, __VA_ARGS__) +#else +#define LOGDI(...) +#define LOGNI(...) +#endif +#define LOGDE(...) dev_err(&priv_data->spidev->dev, __VA_ARGS__) +#define LOGNE(...) netdev_err(netdev, __VA_ARGS__) + +#define MAX_TX_BUFFERS 1 +#define XFER_BUFFER_SIZE 64 +#define K61_CLOCK 120000000 +#define K61_MAX_CHANNELS 1 +#define K61_FW_QUERY_RETRY_COUNT 3 + +struct k61_can { + struct net_device *netdev; + struct spi_device *spidev; + + struct mutex spi_lock; /* SPI device lock */ + + struct workqueue_struct *tx_wq; + char *tx_buf, *rx_buf; + int xfer_length; + atomic_t msg_seq; + + atomic_t netif_queue_stop; + struct completion response_completion; + int reset; + int wait_cmd; + int cmd_result; + int bits_per_word; + int reset_delay_msec; +}; + +struct k61_netdev_privdata { + struct can_priv can; + struct k61_can *k61_can; +}; + +struct k61_tx_work { + struct work_struct work; + struct sk_buff *skb; + struct net_device *netdev; +}; + +/* Message definitions */ +struct spi_mosi { /* TLV for MOSI line */ + u8 cmd; + u8 len; + u16 seq; + u8 data[]; +} __packed; + +struct spi_miso { /* TLV for MISO line */ + u8 cmd; + u8 len; + u16 seq; /* should match seq field from request, or 0 for unsols */ + u8 data[]; +} __packed; + +#define CMD_GET_FW_VERSION 0x81 +#define CMD_CAN_SEND_FRAME 0x82 +#define CMD_CAN_ADD_FILTER 0x83 +#define CMD_CAN_REMOVE_FILTER 0x84 +#define CMD_CAN_RECEIVE_FRAME 0x85 +#define CMD_CAN_DATA_BUFF_ADD 0x87 +#define CMD_CAN_DATA_BUFF_REMOVE 0x88 +#define CMD_CAN_RELEASE_BUFFER 0x89 +#define CMD_CAN_DATA_BUFF_REMOVE_ALL 0x8A + +#define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) +#define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) +#define IOCTL_ADD_FRAME_FILTER (SIOCDEVPRIVATE + 2) +#define IOCTL_REMOVE_FRAME_FILTER (SIOCDEVPRIVATE + 3) +#define IOCTL_DISABLE_BUFFERING (SIOCDEVPRIVATE + 5) +#define IOCTL_DISABLE_ALL_BUFFERING (SIOCDEVPRIVATE + 6) + +struct can_fw_resp { + u8 maj; + u8 min; + u8 ver; +} __packed; + +struct can_write_req { + u32 ts; + u32 mid; + u8 dlc; + u8 data[]; +} __packed; + +struct can_write_resp { + u8 err; +} __packed; + +struct can_receive_frame { + u32 ts; + u32 mid; + u8 dlc; + u8 data[]; +} __packed; + +struct can_add_filter_req { + u8 can_if; + u32 mid; + u32 mask; + u8 type; +} __packed; + +static struct can_bittiming_const k61_bittiming_const = { + .name = "k61", + .tseg1_min = 4, + .tseg1_max = 16, + .tseg2_min = 2, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 4, + .brp_max = 1023, + .brp_inc = 1, +}; + +struct k61_add_can_buffer { + u8 can_if; + u32 mid; + u32 mask; +} __packed; + +struct k61_delete_can_buffer { + u8 can_if; + u32 mid; + u32 mask; +} __packed; + +static int k61_rx_message(struct k61_can *priv_data); + +static irqreturn_t k61_irq(int irq, void *priv) +{ + struct k61_can *priv_data = priv; + + LOGDI("k61_irq\n"); + k61_rx_message(priv_data); + return IRQ_HANDLED; +} + +static void k61_frame_error(struct k61_can *priv_data, + struct can_receive_frame *frame) +{ + struct can_frame *cf; + struct sk_buff *skb; + struct net_device *netdev; + + netdev = priv_data->netdev; + skb = alloc_can_err_skb(netdev, &cf); + if (!skb) { + LOGDE("skb alloc failed\n"); + return; + } + + cf->can_id |= CAN_ERR_BUSERROR; + cf->data[2] |= CAN_ERR_PROT_FORM; + netdev->stats.rx_errors++; + netif_rx(skb); + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += cf->can_dlc; +} + +static void k61_receive_frame(struct k61_can *priv_data, + struct can_receive_frame *frame) +{ + struct can_frame *cf; + struct sk_buff *skb; + struct skb_shared_hwtstamps *skt; + struct timeval tv; + static int msec; + struct net_device *netdev; + int i; + + if (frame->dlc > 8) { + LOGDE("can rx frame error\n"); + k61_frame_error(priv_data, frame); + return; + } + + netdev = priv_data->netdev; + skb = alloc_can_skb(netdev, &cf); + if (!skb) { + LOGDE("skb alloc failed\n"); + return; + } + + LOGDI("rcv frame %d %x %d %x %x %x %x %x %x %x %x\n", + frame->ts, frame->mid, frame->dlc, frame->data[0], + frame->data[1], frame->data[2], frame->data[3], frame->data[4], + frame->data[5], frame->data[6], frame->data[7]); + cf->can_id = le32_to_cpu(frame->mid); + cf->can_dlc = get_can_dlc(frame->dlc); + + for (i = 0; i < cf->can_dlc; i++) + cf->data[i] = frame->data[i]; + + msec = le32_to_cpu(frame->ts); + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec - tv.tv_sec * 1000) * 1000; + skt = skb_hwtstamps(skb); + skt->hwtstamp = timeval_to_ktime(tv); + LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp)); + skb->tstamp = timeval_to_ktime(tv); + netif_rx(skb); + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += cf->can_dlc; +} + +static void k61_process_response(struct k61_can *priv_data, + struct spi_miso *resp) +{ + int ret = 0; + + LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq); + if (resp->cmd == CMD_CAN_RECEIVE_FRAME) { + struct can_receive_frame *frame = + (struct can_receive_frame *)&resp->data; + k61_receive_frame(priv_data, frame); + } else if (resp->cmd == CMD_GET_FW_VERSION) { + struct can_fw_resp *fw_resp = (struct can_fw_resp *)resp->data; + + dev_info(&priv_data->spidev->dev, "fw %d.%d.%d", + fw_resp->maj, fw_resp->min, fw_resp->ver); + } + + if (resp->cmd == priv_data->wait_cmd) { + priv_data->cmd_result = ret; + complete(&priv_data->response_completion); + } +} + +static void k61_process_rx(struct k61_can *priv_data, char *rx_buf) +{ + struct spi_miso *resp; + int length_processed = 0, actual_length = priv_data->xfer_length; + + while (length_processed < actual_length) { + int length_left = actual_length - length_processed; + int length = 0; /* length of consumed chunk */ + void *data; + + data = rx_buf + length_processed; + resp = (struct spi_miso *)data; + + if (resp->cmd == 0) { + /* special case. ignore cmd==0 */ + length_processed += 1; + continue; + } + + LOGDI("processing. p %d -> l %d (t %d)\n", + length_processed, length_left, priv_data->xfer_length); + length = resp->len + sizeof(*resp); + + if (length <= length_left) { + k61_process_response(priv_data, resp); + length_processed += length; + } else { + /* Incomplete command */ + break; + } + } +} + +static int k61_do_spi_transaction(struct k61_can *priv_data) +{ + struct spi_device *spi; + struct spi_transfer *xfer; + struct spi_message *msg; + int ret; + + spi = priv_data->spidev; + msg = devm_kzalloc(&spi->dev, sizeof(*msg), GFP_KERNEL); + xfer = devm_kzalloc(&spi->dev, sizeof(*xfer), GFP_KERNEL); + if (xfer == 0 || msg == 0) + return -ENOMEM; + spi_message_init(msg); + + spi_message_add_tail(xfer, msg); + xfer->tx_buf = priv_data->tx_buf; + xfer->rx_buf = priv_data->rx_buf; + xfer->len = XFER_BUFFER_SIZE; + xfer->bits_per_word = priv_data->bits_per_word; + + ret = spi_sync(spi, msg); + LOGDI("spi_sync ret %d\n", ret); + + if (ret == 0) { + devm_kfree(&spi->dev, msg); + devm_kfree(&spi->dev, xfer); + k61_process_rx(priv_data, priv_data->rx_buf); + } + return ret; +} + +static int k61_rx_message(struct k61_can *priv_data) +{ + char *tx_buf, *rx_buf; + int ret; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + ret = k61_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + +static int k61_query_firmware_version(struct k61_can *priv_data) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = CMD_GET_FW_VERSION; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + priv_data->wait_cmd = CMD_GET_FW_VERSION; + priv_data->cmd_result = -1; + reinit_completion(&priv_data->response_completion); + + ret = k61_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + if (ret == 0) { + wait_for_completion_interruptible_timeout( + &priv_data->response_completion, 0.001 * HZ); + ret = priv_data->cmd_result; + } + + return ret; +} + +static int k61_can_write(struct k61_can *priv_data, struct can_frame *cf) +{ + char *tx_buf, *rx_buf; + int ret, i; + struct spi_mosi *req; + struct can_write_req *req_d; + struct net_device *netdev; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = CMD_CAN_SEND_FRAME; + req->len = sizeof(struct can_write_req) + 8; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + req_d = (struct can_write_req *)req->data; + req_d->mid = cf->can_id; + req_d->dlc = cf->can_dlc; + for (i = 0; i < cf->can_dlc; i++) + req_d->data[i] = cf->data[i]; + + ret = k61_do_spi_transaction(priv_data); + netdev = priv_data->netdev; + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += cf->can_dlc; + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + +static int k61_netdev_open(struct net_device *netdev) +{ + int err; + + LOGNI("Open"); + err = open_candev(netdev); + if (err) + return err; + + netif_start_queue(netdev); + + return 0; +} + +static int k61_netdev_close(struct net_device *netdev) +{ + LOGNI("Close"); + + netif_stop_queue(netdev); + close_candev(netdev); + return 0; +} + +static void k61_send_can_frame(struct work_struct *ws) +{ + struct k61_tx_work *tx_work; + struct can_frame *cf; + struct k61_can *priv_data; + struct net_device *netdev; + struct k61_netdev_privdata *netdev_priv_data; + + tx_work = container_of(ws, struct k61_tx_work, work); + netdev = tx_work->netdev; + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->k61_can; + LOGDI("send_can_frame ws %p\n", ws); + LOGDI("send_can_frame tx %p\n", tx_work); + + cf = (struct can_frame *)tx_work->skb->data; + k61_can_write(priv_data, cf); + + dev_kfree_skb(tx_work->skb); + kfree(tx_work); +} + +static int k61_frame_filter(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + struct can_add_filter_req *add_filter; + struct can_add_filter_req *filter_request; + struct k61_can *priv_data; + struct k61_netdev_privdata *netdev_priv_data; + struct spi_device *spi; + + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->k61_can; + spi = priv_data->spidev; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + if (!ifr) + return -EINVAL; + + filter_request = + devm_kzalloc(&spi->dev, sizeof(struct can_add_filter_req), + GFP_KERNEL); + if (!filter_request) + return -ENOMEM; + + if (copy_from_user(filter_request, ifr->ifr_data, + sizeof(struct can_add_filter_req))) { + devm_kfree(&spi->dev, filter_request); + return -EFAULT; + } + + req = (struct spi_mosi *)tx_buf; + if (cmd == IOCTL_ADD_FRAME_FILTER) + req->cmd = CMD_CAN_ADD_FILTER; + else + req->cmd = CMD_CAN_REMOVE_FILTER; + + req->len = sizeof(struct can_add_filter_req); + req->seq = atomic_inc_return(&priv_data->msg_seq); + + add_filter = (struct can_add_filter_req *)req->data; + add_filter->can_if = filter_request->can_if; + add_filter->mid = filter_request->mid; + add_filter->mask = filter_request->mask; + + ret = k61_do_spi_transaction(priv_data); + devm_kfree(&spi->dev, filter_request); + mutex_unlock(&priv_data->spi_lock); + return ret; +} + +static netdev_tx_t k61_netdev_start_xmit( + struct sk_buff *skb, struct net_device *netdev) +{ + struct k61_netdev_privdata *netdev_priv_data = netdev_priv(netdev); + struct k61_can *priv_data = netdev_priv_data->k61_can; + struct k61_tx_work *tx_work; + + LOGNI("netdev_start_xmit"); + if (can_dropped_invalid_skb(netdev, skb)) { + LOGNE("Dropping invalid can frame\n"); + return NETDEV_TX_OK; + } + tx_work = kzalloc(sizeof(*tx_work), GFP_ATOMIC); + if (tx_work == 0) + return NETDEV_TX_OK; + INIT_WORK(&tx_work->work, k61_send_can_frame); + tx_work->netdev = netdev; + tx_work->skb = skb; + queue_work(priv_data->tx_wq, &tx_work->work); + + return NETDEV_TX_OK; +} + +static int k61_send_release_can_buffer_cmd(struct net_device *netdev) +{ + struct k61_can *priv_data; + struct k61_netdev_privdata *netdev_priv_data; + struct spi_device *spi; + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->k61_can; + spi = priv_data->spidev; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = CMD_CAN_RELEASE_BUFFER; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + ret = k61_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + return ret; +} + +static int k61_remove_all_buffering(struct net_device *netdev) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + struct k61_can *priv_data; + struct k61_netdev_privdata *netdev_priv_data; + + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->k61_can; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = CMD_CAN_DATA_BUFF_REMOVE_ALL; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + priv_data->wait_cmd = req->cmd; + priv_data->cmd_result = -1; + reinit_completion(&priv_data->response_completion); + + ret = k61_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + if (ret == 0) { + LOGDI("k61_do_blocking_ioctl ready to wait for response\n"); + /* Flash write may take some time. Hence give 2s as + * wait duration in the worst case. This wait time should + * increase if more number of frame IDs are stored in flash. + */ + ret = wait_for_completion_interruptible_timeout( + &priv_data->response_completion, 2 * HZ); + ret = priv_data->cmd_result; + } + + return ret; +} + +static int k61_convert_ioctl_cmd_to_spi_cmd(int ioctl_cmd) +{ + switch (ioctl_cmd) { + case IOCTL_ENABLE_BUFFERING: + return CMD_CAN_DATA_BUFF_ADD; + case IOCTL_DISABLE_BUFFERING: + return CMD_CAN_DATA_BUFF_REMOVE; + } + return -EINVAL; +} + +static int k61_data_buffering(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + int spi_cmd, ret; + char *tx_buf, *rx_buf; + struct k61_can *priv_data; + struct spi_mosi *req; + struct k61_netdev_privdata *netdev_priv_data; + struct k61_add_can_buffer *enable_buffering; + struct k61_add_can_buffer *add_request; + struct spi_device *spi; + + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->k61_can; + spi = priv_data->spidev; + + mutex_lock(&priv_data->spi_lock); + spi_cmd = k61_convert_ioctl_cmd_to_spi_cmd(cmd); + if (spi_cmd < 0) { + LOGDE("k61_do_blocking_ioctl wrong command %d\n", cmd); + return spi_cmd; + } + + if (!ifr) + return -EINVAL; + + add_request = devm_kzalloc(&spi->dev, sizeof(struct k61_add_can_buffer), + GFP_KERNEL); + if (!add_request) + return -ENOMEM; + + if (copy_from_user(add_request, ifr->ifr_data, + sizeof(struct k61_add_can_buffer))) { + devm_kfree(&spi->dev, add_request); + return -EFAULT; + } + + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = spi_cmd; + req->len = sizeof(struct k61_add_can_buffer); + req->seq = atomic_inc_return(&priv_data->msg_seq); + + enable_buffering = (struct k61_add_can_buffer *)req->data; + enable_buffering->can_if = add_request->can_if; + enable_buffering->mid = add_request->mid; + enable_buffering->mask = add_request->mask; + + priv_data->wait_cmd = spi_cmd; + priv_data->cmd_result = -1; + reinit_completion(&priv_data->response_completion); + + ret = k61_do_spi_transaction(priv_data); + devm_kfree(&spi->dev, add_request); + mutex_unlock(&priv_data->spi_lock); + + if (ret == 0) { + LOGDI("k61_do_blocking_ioctl ready to wait for response\n"); + /* Flash write may take some time. Hence give 400ms as + * wait duration in the worst case. + */ + ret = wait_for_completion_interruptible_timeout( + &priv_data->response_completion, 0.4 * HZ); + ret = priv_data->cmd_result; + } + return ret; +} + +static int k61_netdev_do_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + struct k61_can *priv_data; + struct k61_netdev_privdata *netdev_priv_data; + int ret = -EINVAL; + + netdev_priv_data = netdev_priv(netdev); + priv_data = netdev_priv_data->k61_can; + LOGDI("k61_netdev_do_ioctl %x\n", cmd); + + switch (cmd) { + case IOCTL_ADD_FRAME_FILTER: + case IOCTL_REMOVE_FRAME_FILTER: + ret = k61_frame_filter(netdev, ifr, cmd); + break; + case IOCTL_ENABLE_BUFFERING: + case IOCTL_DISABLE_BUFFERING: + ret = k61_data_buffering(netdev, ifr, cmd); + break; + case IOCTL_DISABLE_ALL_BUFFERING: + ret = k61_remove_all_buffering(netdev); + break; + case IOCTL_RELEASE_CAN_BUFFER: + ret = k61_send_release_can_buffer_cmd(netdev); + break; + } + return ret; +} + +static const struct net_device_ops k61_netdev_ops = { + .ndo_open = k61_netdev_open, + .ndo_stop = k61_netdev_close, + .ndo_start_xmit = k61_netdev_start_xmit, + .ndo_do_ioctl = k61_netdev_do_ioctl, +}; + +static int k61_create_netdev(struct spi_device *spi, + struct k61_can *priv_data) +{ + struct net_device *netdev; + struct k61_netdev_privdata *netdev_priv_data; + + LOGDI("k61_create_netdev\n"); + netdev = alloc_candev(sizeof(*netdev_priv_data), MAX_TX_BUFFERS); + if (!netdev) { + LOGDE("Couldn't alloc candev\n"); + return -ENOMEM; + } + + netdev_priv_data = netdev_priv(netdev); + netdev_priv_data->k61_can = priv_data; + + priv_data->netdev = netdev; + + netdev->netdev_ops = &k61_netdev_ops; + SET_NETDEV_DEV(netdev, &spi->dev); + netdev_priv_data->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_LISTENONLY; + netdev_priv_data->can.bittiming_const = &k61_bittiming_const; + netdev_priv_data->can.clock.freq = K61_CLOCK; + + return 0; +} + +static struct k61_can *k61_create_priv_data(struct spi_device *spi) +{ + struct k61_can *priv_data; + int err; + struct device *dev; + + dev = &spi->dev; + priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) { + dev_err(dev, "Couldn't alloc k61_can\n"); + return 0; + } + spi_set_drvdata(spi, priv_data); + atomic_set(&priv_data->netif_queue_stop, 0); + priv_data->spidev = spi; + + priv_data->tx_wq = alloc_workqueue("k61_tx_wq", 0, 0); + if (!priv_data->tx_wq) { + dev_err(dev, "Couldn't alloc workqueue\n"); + err = -ENOMEM; + goto cleanup_privdata; + } + + priv_data->tx_buf = devm_kzalloc(dev, XFER_BUFFER_SIZE, + GFP_KERNEL); + priv_data->rx_buf = devm_kzalloc(dev, XFER_BUFFER_SIZE, + GFP_KERNEL); + if (!priv_data->tx_buf || !priv_data->rx_buf) { + dev_err(dev, "Couldn't alloc tx or rx buffers\n"); + err = -ENOMEM; + goto cleanup_privdata; + } + priv_data->xfer_length = 0; + + mutex_init(&priv_data->spi_lock); + atomic_set(&priv_data->msg_seq, 0); + init_completion(&priv_data->response_completion); + return priv_data; + +cleanup_privdata: + if (priv_data) { + if (priv_data->tx_wq) + destroy_workqueue(priv_data->tx_wq); + } + return 0; +} + +static int k61_probe(struct spi_device *spi) +{ + int err, retry = 0, query_err = -1; + struct k61_can *priv_data; + struct device *dev; + + dev = &spi->dev; + dev_dbg(dev, "k61_probe"); + + err = spi_setup(spi); + if (err) { + dev_err(dev, "spi_setup failed: %d", err); + return err; + } + + priv_data = k61_create_priv_data(spi); + if (!priv_data) { + dev_err(dev, "Failed to create k61_can priv_data\n"); + err = -ENOMEM; + return err; + } + dev_dbg(dev, "k61_probe created priv_data"); + + err = of_property_read_u32(spi->dev.of_node, "bits-per-word", + &priv_data->bits_per_word); + if (err) + priv_data->bits_per_word = 16; + + err = of_property_read_u32(spi->dev.of_node, "reset-delay-msec", + &priv_data->reset_delay_msec); + if (err) + priv_data->reset_delay_msec = 1; + + priv_data->reset = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); + if (gpio_is_valid(priv_data->reset)) { + err = gpio_request(priv_data->reset, "k61-reset"); + if (err < 0) { + dev_err(&spi->dev, + "failed to request gpio %d: %d\n", + priv_data->reset, err); + goto cleanup_candev; + } + + gpio_direction_output(priv_data->reset, 0); + udelay(1); + gpio_direction_output(priv_data->reset, 1); + msleep(priv_data->reset_delay_msec); + } + + err = k61_create_netdev(spi, priv_data); + if (err) { + dev_err(dev, "Failed to create CAN device: %d", err); + goto cleanup_candev; + } + + err = register_candev(priv_data->netdev); + if (err) { + dev_err(dev, "Failed to register CAN device: %d", err); + goto unregister_candev; + } + + err = request_threaded_irq(spi->irq, NULL, k61_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "k61", priv_data); + if (err) { + dev_err(dev, "Failed to request irq: %d", err); + goto unregister_candev; + } + dev_dbg(dev, "Request irq %d ret %d\n", spi->irq, err); + + while ((query_err != 0) && (retry < K61_FW_QUERY_RETRY_COUNT)) { + query_err = k61_query_firmware_version(priv_data); + retry++; + } + + if (query_err) { + dev_info(dev, "K61 probe failed\n"); + err = -ENODEV; + goto free_irq; + } + return 0; + +free_irq: + free_irq(spi->irq, priv_data); +unregister_candev: + unregister_candev(priv_data->netdev); +cleanup_candev: + if (priv_data) { + if (priv_data->netdev) + free_candev(priv_data->netdev); + if (priv_data->tx_wq) + destroy_workqueue(priv_data->tx_wq); + } + return err; +} + +static int k61_remove(struct spi_device *spi) +{ + struct k61_can *priv_data = spi_get_drvdata(spi); + + LOGDI("k61_remove\n"); + unregister_candev(priv_data->netdev); + free_candev(priv_data->netdev); + destroy_workqueue(priv_data->tx_wq); + return 0; +} + +static const struct of_device_id k61_match_table[] = { + { .compatible = "fsl,k61" }, + { .compatible = "nxp,mpc5746c" }, + { } +}; + +static struct spi_driver k61_driver = { + .driver = { + .name = "k61", + .of_match_table = k61_match_table, + .owner = THIS_MODULE, + }, + .probe = k61_probe, + .remove = k61_remove, +}; +module_spi_driver(k61_driver); + +MODULE_DESCRIPTION("Freescale K61 SPI-CAN module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index ecc4a334c507..0a54e7dac0ab 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -608,7 +608,7 @@ static void nb8800_mac_config(struct net_device *dev) mac_mode |= HALF_DUPLEX; if (gigabit) { - if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (phy_interface_is_rgmii(dev->phydev)) mac_mode |= RGMII_MODE; mac_mode |= GMAC_MODE; @@ -1295,11 +1295,10 @@ static int nb8800_tangox_init(struct net_device *dev) break; case PHY_INTERFACE_MODE_RGMII: - pad_mode = PAD_MODE_RGMII; - break; - + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: - pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY; + pad_mode = PAD_MODE_RGMII; break; default: diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 21e5b9ed1ead..3613469dc5c6 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8722,11 +8722,14 @@ static void tg3_free_consistent(struct tg3 *tp) tg3_mem_rx_release(tp); tg3_mem_tx_release(tp); + /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */ + tg3_full_lock(tp, 0); if (tp->hw_stats) { dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats), tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } + tg3_full_unlock(tp); } /* diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index cc199063612a..6c66d2979795 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -630,6 +630,10 @@ static void dump_command(struct mlx5_core_dev *dev, pr_debug("\n"); } +static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg); +static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev, + struct mlx5_cmd_msg *msg); + static void cmd_work_handler(struct work_struct *work) { struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work); @@ -638,16 +642,27 @@ static void cmd_work_handler(struct work_struct *work) struct mlx5_cmd_layout *lay; struct semaphore *sem; unsigned long flags; + int alloc_ret; sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem; down(sem); if (!ent->page_queue) { - ent->idx = alloc_ent(cmd); - if (ent->idx < 0) { + alloc_ret = alloc_ent(cmd); + if (alloc_ret < 0) { + if (ent->callback) { + ent->callback(-EAGAIN, ent->context); + mlx5_free_cmd_msg(dev, ent->out); + free_msg(dev, ent->in); + free_cmd(ent); + } else { + ent->ret = -EAGAIN; + complete(&ent->done); + } mlx5_core_err(dev, "failed to allocate command entry\n"); up(sem); return; } + ent->idx = alloc_ret; } else { ent->idx = cmd->max_reg_cmds; spin_lock_irqsave(&cmd->alloc_lock, flags); diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 4296066a7ad3..479af106aaeb 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -819,6 +819,7 @@ static struct sh_eth_cpu_data r8a7740_data = { .rpadir_value = 2 << 16, .no_trimd = 1, .no_ade = 1, + .hw_crc = 1, .tsu = 1, .select_mii = 1, .shift_rd0 = 1, diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index bca6a1e72d1d..e1bb802d4a4d 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -141,9 +141,19 @@ static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val) static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val) { struct usb_device *dev = mcs->usbdev; - int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, - MCS_RD_RTYPE, 0, reg, val, 2, - msecs_to_jiffies(MCS_CTRL_TIMEOUT)); + void *dmabuf; + int ret; + + dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, + MCS_RD_RTYPE, 0, reg, dmabuf, 2, + msecs_to_jiffies(MCS_CTRL_TIMEOUT)); + + memcpy(val, dmabuf, sizeof(__u16)); + kfree(dmabuf); return ret; } diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 32f10662f4ac..7242dd4b3238 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -29,6 +29,7 @@ #define MII_DP83867_MICR 0x12 #define MII_DP83867_ISR 0x13 #define DP83867_CTRL 0x1f +#define DP83867_CFG3 0x1e /* Extended Registers */ #define DP83867_RGMIICTL 0x0032 @@ -89,6 +90,8 @@ static int dp83867_config_intr(struct phy_device *phydev) micr_status |= (MII_DP83867_MICR_AN_ERR_INT_EN | MII_DP83867_MICR_SPEED_CHNG_INT_EN | + MII_DP83867_MICR_AUTONEG_COMP_INT_EN | + MII_DP83867_MICR_LINK_STS_CHNG_INT_EN | MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN | MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN); @@ -184,6 +187,13 @@ static int dp83867_config_init(struct phy_device *phydev) DP83867_DEVADDR, phydev->addr, delay); } + /* Enable Interrupt output INT_OE in CFG3 register */ + if (phy_interrupt_is_valid(phydev)) { + val = phy_read(phydev, DP83867_CFG3); + val |= BIT(7); + phy_write(phydev, DP83867_CFG3, val); + } + return 0; } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 851c0e121807..49d9f0a789fe 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -541,6 +541,9 @@ void phy_stop_machine(struct phy_device *phydev) if (phydev->state > PHY_UP && phydev->state != PHY_HALTED) phydev->state = PHY_UP; mutex_unlock(&phydev->lock); + + /* Now we can run the state machine synchronously */ + phy_state_machine(&phydev->state_queue.work); } /** @@ -918,6 +921,15 @@ void phy_state_machine(struct work_struct *work) if (old_link != phydev->link) phydev->state = PHY_CHANGELINK; } + /* + * Failsafe: check that nobody set phydev->link=0 between two + * poll cycles, otherwise we won't leave RUNNING state as long + * as link remains down. + */ + if (!phydev->link && phydev->state == PHY_RUNNING) { + phydev->state = PHY_CHANGELINK; + dev_err(&phydev->dev, "no link in PHY_RUNNING\n"); + } break; case PHY_CHANGELINK: err = phy_read_status(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1d1e5f7723ab..8179727d3423 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1368,6 +1368,8 @@ static int phy_remove(struct device *dev) { struct phy_device *phydev = to_phy_device(dev); + cancel_delayed_work_sync(&phydev->state_queue); + mutex_lock(&phydev->lock); phydev->state = PHY_DOWN; mutex_unlock(&phydev->lock); diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 10223605b027..dd310d5a7028 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -719,6 +719,7 @@ static int ath10k_snoc_driver_event_server_exit(struct ath10k *ar) atomic_set(&qmi_cfg->fw_ready, 0); qmi_cfg->msa_ready = false; atomic_set(&qmi_cfg->server_connected, 0); + qmi_handle_destroy(qmi_cfg->wlfw_clnt); return 0; } @@ -896,5 +897,6 @@ void ath10k_snoc_stop_qmi_service(struct ath10k *ar) WLFW_SERVICE_INS_ID_V01, &qmi_cfg->wlfw_clnt_nb); destroy_workqueue(qmi_cfg->event_wq); + qmi_handle_destroy(qmi_cfg->wlfw_clnt); qmi_cfg = NULL; } diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 0e66348e7513..2ab6c5951561 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -60,3 +60,15 @@ config WIL6210_PLATFORM_MSM ---help--- Say Y here to enable wil6210 driver support for MSM platform specific features + +config WIL6210_DEBUGFS + bool "wil6210 debugfs support" + depends on WIL6210 + depends on DEBUG_FS + default y + ---help--- + Say Y here to enable wil6210 debugfs support, using the + kernel debugfs infrastructure. Select this + option if you are interested in debugging the driver. + + If unsure, say Y to make it easier to debug problems. diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 4874c5ba1e61..94df1decae7a 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -4,7 +4,7 @@ wil6210-y := main.o wil6210-y += netdev.o wil6210-y += cfg80211.o wil6210-y += pcie_bus.o -wil6210-y += debugfs.o +wil6210-$(CONFIG_WIL6210_DEBUGFS) += debugfs.o wil6210-y += sysfs.o wil6210-y += wmi.o wil6210-y += interrupt.o diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 93868095dc3c..35dfa410c90c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -455,6 +455,34 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, return rc; } +static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + wil_dbg_misc(wil, "start_p2p_device: entered\n"); + wil->p2p.p2p_dev_started = 1; + return 0; +} + +static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil_p2p_info *p2p = &wil->p2p; + + if (!p2p->p2p_dev_started) + return; + + wil_dbg_misc(wil, "stop_p2p_device: entered\n"); + mutex_lock(&wil->mutex); + mutex_lock(&wil->p2p_wdev_mutex); + wil_p2p_stop_radio_operations(wil); + p2p->p2p_dev_started = 0; + mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->mutex); +} + static struct wireless_dev * wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, @@ -503,6 +531,7 @@ static int wil_cfg80211_del_iface(struct wiphy *wiphy, return -EINVAL; } + wil_cfg80211_stop_p2p_device(wiphy, wdev); wil_p2p_wdev_free(wil); return 0; @@ -887,7 +916,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, wil->bss = bss; /* Connect can take lots of time */ mod_timer(&wil->connect_timer, - jiffies + msecs_to_jiffies(2000)); + jiffies + msecs_to_jiffies(5000)); } else { clear_bit(wil_status_fwconnecting, wil->status); } @@ -1737,34 +1766,6 @@ static int wil_cfg80211_change_bss(struct wiphy *wiphy, return 0; } -static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, - struct wireless_dev *wdev) -{ - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - - wil_dbg_misc(wil, "start_p2p_device: entered\n"); - wil->p2p.p2p_dev_started = 1; - return 0; -} - -static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, - struct wireless_dev *wdev) -{ - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wil_p2p_info *p2p = &wil->p2p; - - if (!p2p->p2p_dev_started) - return; - - wil_dbg_misc(wil, "stop_p2p_device: entered\n"); - mutex_lock(&wil->mutex); - mutex_lock(&wil->p2p_wdev_mutex); - wil_p2p_stop_radio_operations(wil); - p2p->p2p_dev_started = 0; - mutex_unlock(&wil->p2p_wdev_mutex); - mutex_unlock(&wil->mutex); -} - static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index cad8a95c4e4e..59def4f3fcf3 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -244,7 +244,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); if (unlikely(!isr)) { - wil_err(wil, "spurious IRQ: RX\n"); + wil_err_ratelimited(wil, "spurious IRQ: RX\n"); return IRQ_NONE; } @@ -269,11 +269,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) need_unmask = false; napi_schedule(&wil->napi_rx); } else { - wil_err(wil, + wil_err_ratelimited( + wil, "Got Rx interrupt while stopping interface\n"); } } else { - wil_err(wil, "Got Rx interrupt while in reset\n"); + wil_err_ratelimited(wil, "Got Rx interrupt while in reset\n"); } } @@ -302,7 +303,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); if (unlikely(!isr)) { - wil_err(wil, "spurious IRQ: TX\n"); + wil_err_ratelimited(wil, "spurious IRQ: TX\n"); return IRQ_NONE; } @@ -318,12 +319,13 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) need_unmask = false; napi_schedule(&wil->napi_tx); } else { - wil_err(wil, "Got Tx interrupt while in reset\n"); + wil_err_ratelimited(wil, "Got Tx interrupt while in reset\n"); } } if (unlikely(isr)) - wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); + wil_err_ratelimited(wil, "un-handled TX ISR bits 0x%08x\n", + isr); /* Tx IRQ will be enabled when NAPI processing finished */ diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 09da8e769394..e39e3dbb62e9 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -931,6 +931,29 @@ int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) return rc; } +static void wil_pre_fw_config(struct wil6210_priv *wil) +{ + /* Mark FW as loaded from host */ + wil_s(wil, RGF_USER_USAGE_6, 1); + + /* clear any interrupts which on-card-firmware + * may have set + */ + wil6210_clear_irq(wil); + /* CAF_ICR - clear and mask */ + /* it is W1C, clear by writing back same value */ + wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + /* clear PAL_UNIT_ICR (potential D0->D3 leftover) */ + wil_s(wil, RGF_PAL_UNIT_ICR + offsetof(struct RGF_ICR, ICR), 0); + + if (wil->fw_calib_result > 0) { + __le32 val = cpu_to_le32(wil->fw_calib_result | + (CALIB_RESULT_SIGNATURE << 8)); + wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val); + } +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -1028,24 +1051,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (rc) return rc; - /* Mark FW as loaded from host */ - wil_s(wil, RGF_USER_USAGE_6, 1); - - /* clear any interrupts which on-card-firmware - * may have set - */ - wil6210_clear_irq(wil); - /* CAF_ICR - clear and mask */ - /* it is W1C, clear by writing back same value */ - wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); - wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); - - if (wil->fw_calib_result > 0) { - __le32 val = cpu_to_le32(wil->fw_calib_result | - (CALIB_RESULT_SIGNATURE << 8)); - wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val); - } - + wil_pre_fw_config(wil); wil_release_cpu(wil); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c9ab282c161a..673a953fcf6e 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -275,6 +275,7 @@ struct RGF_ICR { #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) #define RGF_HP_CTRL (0x88265c) +#define RGF_PAL_UNIT_ICR (0x88266c) /* struct RGF_ICR */ #define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) /* MAC timer, usec, for packet lifetime */ @@ -954,8 +955,13 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params, u64 *cookie); +#if defined(CONFIG_WIL6210_DEBUGFS) int wil6210_debugfs_init(struct wil6210_priv *wil); void wil6210_debugfs_remove(struct wil6210_priv *wil); +#else +static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; } +static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {} +#endif int wil6210_sysfs_init(struct wil6210_priv *wil); void wil6210_sysfs_remove(struct wil6210_priv *wil); int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 1b426d7ef81f..5263ee717a4f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -36,6 +36,11 @@ #define WMI_PROX_RANGE_NUM (3) #define WMI_MAX_LOSS_DMG_BEACONS (20) #define MAX_NUM_OF_SECTORS (128) +#define WMI_SCHED_MAX_ALLOCS_PER_CMD (4) +#define WMI_RF_DTYPE_LENGTH (3) +#define WMI_RF_ETYPE_LENGTH (3) +#define WMI_RF_RX2TX_LENGTH (3) +#define WMI_RF_ETYPE_VAL_PER_RANGE (5) /* Mailbox interface * used for commands and events @@ -52,15 +57,20 @@ enum wmi_mid { * the host */ enum wmi_fw_capability { - WMI_FW_CAPABILITY_FTM = 0, - WMI_FW_CAPABILITY_PS_CONFIG = 1, - WMI_FW_CAPABILITY_RF_SECTORS = 2, - 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_D3_SUSPEND = 8, - WMI_FW_CAPABILITY_RSSI_REPORTING = 12, + WMI_FW_CAPABILITY_FTM = 0, + WMI_FW_CAPABILITY_PS_CONFIG = 1, + WMI_FW_CAPABILITY_RF_SECTORS = 2, + 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_D3_SUSPEND = 8, + WMI_FW_CAPABILITY_LONG_RANGE = 9, + WMI_FW_CAPABILITY_FIXED_SCHEDULING = 10, + WMI_FW_CAPABILITY_MULTI_DIRECTED_OMNIS = 11, + WMI_FW_CAPABILITY_RSSI_REPORTING = 12, + WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13, + WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14, WMI_FW_CAPABILITY_MAX, }; @@ -80,6 +90,7 @@ enum wmi_command_id { WMI_START_SCAN_CMDID = 0x07, WMI_SET_BSS_FILTER_CMDID = 0x09, WMI_SET_PROBED_SSID_CMDID = 0x0A, + /* deprecated */ WMI_SET_LISTEN_INT_CMDID = 0x0B, WMI_BCON_CTRL_CMDID = 0x0F, WMI_ADD_CIPHER_KEY_CMDID = 0x16, @@ -94,26 +105,28 @@ enum wmi_command_id { WMI_ECHO_CMDID = 0x803, WMI_DEEP_ECHO_CMDID = 0x804, WMI_CONFIG_MAC_CMDID = 0x805, + /* deprecated */ WMI_CONFIG_PHY_DEBUG_CMDID = 0x806, WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808, WMI_PHY_GET_STATISTICS_CMDID = 0x809, + /* deprecated */ WMI_FS_TUNE_CMDID = 0x80A, + /* deprecated */ WMI_CORR_MEASURE_CMDID = 0x80B, WMI_READ_RSSI_CMDID = 0x80C, WMI_TEMP_SENSE_CMDID = 0x80E, WMI_DC_CALIB_CMDID = 0x80F, + /* deprecated */ WMI_SEND_TONE_CMDID = 0x810, + /* deprecated */ WMI_IQ_TX_CALIB_CMDID = 0x811, + /* deprecated */ WMI_IQ_RX_CALIB_CMDID = 0x812, - WMI_SET_UCODE_IDLE_CMDID = 0x813, WMI_SET_WORK_MODE_CMDID = 0x815, WMI_LO_LEAKAGE_CALIB_CMDID = 0x816, - WMI_MARLON_R_READ_CMDID = 0x818, - WMI_MARLON_R_WRITE_CMDID = 0x819, - WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A, - MAC_IO_STATIC_PARAMS_CMDID = 0x81B, - MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C, + WMI_LO_POWER_CALIB_FROM_OTP_CMDID = 0x817, WMI_SILENT_RSSI_CALIB_CMDID = 0x81D, + /* deprecated */ WMI_RF_RX_TEST_CMDID = 0x81E, WMI_CFG_RX_CHAIN_CMDID = 0x820, WMI_VRING_CFG_CMDID = 0x821, @@ -127,11 +140,6 @@ enum wmi_command_id { WMI_SET_PCP_CHANNEL_CMDID = 0x829, WMI_GET_PCP_CHANNEL_CMDID = 0x82A, WMI_SW_TX_REQ_CMDID = 0x82B, - WMI_READ_MAC_RXQ_CMDID = 0x830, - WMI_READ_MAC_TXQ_CMDID = 0x831, - WMI_WRITE_MAC_RXQ_CMDID = 0x832, - WMI_WRITE_MAC_TXQ_CMDID = 0x833, - WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834, WMI_MLME_PUSH_CMDID = 0x835, WMI_BEAMFORMING_MGMT_CMDID = 0x836, WMI_BF_TXSS_MGMT_CMDID = 0x837, @@ -145,9 +153,13 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x851, WMI_RS_MGMT_CMDID = 0x852, WMI_RF_MGMT_CMDID = 0x853, - WMI_OTP_READ_CMDID = 0x856, - WMI_OTP_WRITE_CMDID = 0x857, + WMI_RF_XPM_READ_CMDID = 0x856, + WMI_RF_XPM_WRITE_CMDID = 0x857, WMI_LED_CFG_CMDID = 0x858, + WMI_SET_CONNECT_SNR_THR_CMDID = 0x85B, + WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID = 0x85C, + WMI_RF_PWR_ON_DELAY_CMDID = 0x85D, + WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID = 0x85E, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x862, WMI_NOTIFY_REQ_CMDID = 0x863, @@ -155,7 +167,6 @@ enum wmi_command_id { WMI_GET_RF_STATUS_CMDID = 0x866, WMI_GET_BASEBAND_TYPE_CMDID = 0x867, WMI_UNIT_TEST_CMDID = 0x900, - WMI_HICCUP_CMDID = 0x901, WMI_FLASH_READ_CMDID = 0x902, WMI_FLASH_WRITE_CMDID = 0x903, /* Power management */ @@ -175,16 +186,6 @@ enum wmi_command_id { WMI_GET_PCP_FACTOR_CMDID = 0x91B, /* Power Save Configuration Commands */ WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C, - /* Not supported yet */ - WMI_PS_DEV_CFG_CMDID = 0x91D, - /* Not supported yet */ - WMI_PS_DEV_CFG_READ_CMDID = 0x91E, - /* Per MAC Power Save Configuration commands - * Not supported yet - */ - WMI_PS_MID_CFG_CMDID = 0x91F, - /* Not supported yet */ - WMI_PS_MID_CFG_READ_CMDID = 0x920, WMI_RS_CFG_CMDID = 0x921, WMI_GET_DETAILED_RS_RES_CMDID = 0x922, WMI_AOA_MEAS_CMDID = 0x923, @@ -195,13 +196,16 @@ enum wmi_command_id { WMI_DEL_STA_CMDID = 0x936, WMI_SET_THERMAL_THROTTLING_CFG_CMDID = 0x940, WMI_GET_THERMAL_THROTTLING_CFG_CMDID = 0x941, + /* Read Power Save profile type */ + WMI_PS_DEV_PROFILE_CFG_READ_CMDID = 0x942, WMI_TOF_SESSION_START_CMDID = 0x991, WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, WMI_TOF_SET_LCR_CMDID = 0x993, WMI_TOF_SET_LCI_CMDID = 0x994, - WMI_TOF_CHANNEL_INFO_CMDID = 0x995, + WMI_TOF_CFG_RESPONDER_CMDID = 0x996, WMI_TOF_SET_TX_RX_OFFSET_CMDID = 0x997, WMI_TOF_GET_TX_RX_OFFSET_CMDID = 0x998, + WMI_TOF_CHANNEL_INFO_CMDID = 0x999, WMI_GET_RF_SECTOR_PARAMS_CMDID = 0x9A0, WMI_SET_RF_SECTOR_PARAMS_CMDID = 0x9A1, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A2, @@ -210,12 +214,20 @@ enum wmi_command_id { WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, + WMI_SCHEDULING_SCHEME_CMDID = 0xA01, + WMI_FIXED_SCHEDULING_CONFIG_CMDID = 0xA02, + WMI_ENABLE_FIXED_SCHEDULING_CMDID = 0xA03, + WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID = 0xA04, + WMI_SET_LONG_RANGE_CONFIG_CMDID = 0xA05, WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_ABORT_SCAN_CMDID = 0xF007, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, + /* deprecated */ WMI_GET_PMK_CMDID = 0xF048, WMI_SET_PASSPHRASE_CMDID = 0xF049, + /* deprecated */ WMI_SEND_ASSOC_RES_CMDID = 0xF04A, + /* deprecated */ WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B, WMI_MAC_ADDR_REQ_CMDID = 0xF04D, WMI_FW_VER_CMDID = 0xF04E, @@ -441,11 +453,6 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; -/* WMI_RF_RX_TEST_CMDID */ -struct wmi_rf_rx_test_cmd { - __le32 sector; -} __packed; - /* WMI_CORR_MEASURE_CMDID */ struct wmi_corr_measure_cmd { __le32 freq_mhz; @@ -658,6 +665,20 @@ struct wmi_bcast_vring_cfg_cmd { struct wmi_bcast_vring_cfg vring_cfg; } __packed; +/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */ +struct wmi_lo_power_calib_from_otp_cmd { + /* index to read from OTP. zero based */ + u8 index; + u8 reserved[3]; +} __packed; + +/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */ +struct wmi_lo_power_calib_from_otp_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_VRING_BA_EN_CMDID */ struct wmi_vring_ba_en_cmd { u8 ringid; @@ -693,6 +714,24 @@ enum wmi_sniffer_cfg_mode { WMI_SNIFFER_ON = 0x01, }; +/* WMI_SILENT_RSSI_TABLE */ +enum wmi_silent_rssi_table { + RF_TEMPERATURE_CALIB_DEFAULT_DB = 0x00, + RF_TEMPERATURE_CALIB_HIGH_POWER_DB = 0x01, +}; + +/* WMI_SILENT_RSSI_STATUS */ +enum wmi_silent_rssi_status { + SILENT_RSSI_SUCCESS = 0x00, + SILENT_RSSI_FAILURE = 0x01, +}; + +/* WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID */ +struct wmi_set_active_silent_rssi_table_cmd { + /* enum wmi_silent_rssi_table */ + __le32 table; +} __packed; + enum wmi_sniffer_cfg_phy_info_mode { WMI_SNIFFER_PHY_INFO_DISABLED = 0x00, WMI_SNIFFER_PHY_INFO_ENABLED = 0x01, @@ -836,18 +875,85 @@ struct wmi_echo_cmd { __le32 value; } __packed; -/* WMI_OTP_READ_CMDID */ -struct wmi_otp_read_cmd { - __le32 addr; - __le32 size; - __le32 values; +/* WMI_RF_PWR_ON_DELAY_CMDID + * set FW time parameters used through RF resetting + * RF reset consists of bringing its power down for a period of time, then + * bringing the power up + * Returned event: WMI_RF_PWR_ON_DELAY_RSP_EVENTID + */ +struct wmi_rf_pwr_on_delay_cmd { + /* time in usec the FW waits after bringing the RF PWR down, + * set 0 for default + */ + __le16 down_delay_usec; + /* time in usec the FW waits after bringing the RF PWR up, + * set 0 for default + */ + __le16 up_delay_usec; +} __packed; + +/* \WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID + * This API controls the Tx and Rx gain over temperature. + * It controls the Tx D-type, Rx D-type and Rx E-type amplifiers. + * It also controls the Tx gain index, by controlling the Rx to Tx gain index + * offset. + * The control is divided by 3 temperature values to 4 temperature ranges. + * Each parameter uses its own temperature values. + * Returned event: WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID + */ +struct wmi_set_high_power_table_params_cmd { + /* Temperature range for Tx D-type parameters */ + u8 tx_dtype_temp[WMI_RF_DTYPE_LENGTH]; + u8 reserved0; + /* Tx D-type values to be used for each temperature range */ + __le32 tx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1]; + /* Temperature range for Rx D-type parameters */ + u8 rx_dtype_temp[WMI_RF_DTYPE_LENGTH]; + u8 reserved1; + /* Rx D-type values to be used for each temperature range */ + __le32 rx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1]; + /* Temperature range for Rx E-type parameters */ + u8 rx_etype_temp[WMI_RF_ETYPE_LENGTH]; + u8 reserved2; + /* Rx E-type values to be used for each temperature range. + * The last 4 values of any range are the first 4 values of the next + * range and so on + */ + __le32 rx_etype_conf[WMI_RF_ETYPE_VAL_PER_RANGE + WMI_RF_ETYPE_LENGTH]; + /* Temperature range for rx_2_tx_offs parameters */ + u8 rx_2_tx_temp[WMI_RF_RX2TX_LENGTH]; + u8 reserved3; + /* Rx to Tx gain index offset */ + s8 rx_2_tx_offs[WMI_RF_RX2TX_LENGTH + 1]; } __packed; -/* WMI_OTP_WRITE_CMDID */ -struct wmi_otp_write_cmd { - __le32 addr; - __le32 size; - __le32 values; +/* CMD: WMI_RF_XPM_READ_CMDID */ +struct wmi_rf_xpm_read_cmd { + u8 rf_id; + u8 reserved[3]; + /* XPM bit start address in range [0,8191]bits - rounded by FW to + * multiple of 8bits + */ + __le32 xpm_bit_address; + __le32 num_bytes; +} __packed; + +/* CMD: WMI_RF_XPM_WRITE_CMDID */ +struct wmi_rf_xpm_write_cmd { + u8 rf_id; + u8 reserved0[3]; + /* XPM bit start address in range [0,8191]bits - rounded by FW to + * multiple of 8bits + */ + __le32 xpm_bit_address; + __le32 num_bytes; + /* boolean flag indicating whether FW should verify the write + * operation + */ + u8 verify; + u8 reserved1[3]; + /* actual size=num_bytes */ + u8 data_bytes[0]; } __packed; /* WMI_TEMP_SENSE_CMDID @@ -990,19 +1096,26 @@ struct wmi_ftm_dest_info { */ __le16 burst_period; u8 dst_mac[WMI_MAC_LEN]; - __le16 reserved; + u8 reserved; + u8 num_burst_per_aoa_meas; } __packed; /* WMI_TOF_SESSION_START_CMDID */ struct wmi_tof_session_start_cmd { __le32 session_id; - u8 num_of_aoa_measures; + u8 reserved1; u8 aoa_type; __le16 num_of_dest; u8 reserved[4]; struct wmi_ftm_dest_info ftm_dest_info[0]; } __packed; +/* WMI_TOF_CFG_RESPONDER_CMDID */ +struct wmi_tof_cfg_responder_cmd { + u8 enable; + u8 reserved[3]; +} __packed; + enum wmi_tof_channel_info_report_type { WMI_TOF_CHANNEL_INFO_TYPE_CIR = 0x1, WMI_TOF_CHANNEL_INFO_TYPE_RSSI = 0x2, @@ -1023,7 +1136,99 @@ struct wmi_tof_set_tx_rx_offset_cmd { __le32 tx_offset; /* RX delay offset */ __le32 rx_offset; - __le32 reserved[2]; + /* Mask to define which RFs to configure. 0 means all RFs */ + __le32 rf_mask; + /* Offset to strongest tap of CIR */ + __le32 precursor; +} __packed; + +/* WMI_TOF_GET_TX_RX_OFFSET_CMDID */ +struct wmi_tof_get_tx_rx_offset_cmd { + /* rf index to read offsets from */ + u8 rf_index; + u8 reserved[3]; +} __packed; + +/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */ +struct wmi_map_mcs_to_schd_params { + u8 mcs; + /* time in usec from start slot to start tx flow - default 15 */ + u8 time_in_usec_before_initiate_tx; + /* RD enable - if yes consider RD according to STA mcs */ + u8 rd_enabled; + u8 reserved; + /* time in usec from start slot to stop vring */ + __le16 time_in_usec_to_stop_vring; + /* timeout to force flush from start of slot */ + __le16 flush_to_in_usec; + /* per mcs the mac buffer limit size in bytes */ + __le32 mac_buff_size_in_bytes; +} __packed; + +/* WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID */ +struct wmi_fixed_scheduling_config_complete_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +#define WMI_NUM_MCS (13) + +/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */ +struct wmi_fixed_scheduling_config_cmd { + /* defaults in the SAS table */ + struct wmi_map_mcs_to_schd_params mcs_to_schd_params_map[WMI_NUM_MCS]; + /* default 150 uSec */ + __le16 max_sta_rd_ppdu_duration_in_usec; + /* default 300 uSec */ + __le16 max_sta_grant_ppdu_duration_in_usec; + /* default 1000 uSec */ + __le16 assoc_slot_duration_in_usec; + /* default 360 uSec */ + __le16 virtual_slot_duration_in_usec; + /* each this field value slots start with grant frame to the station + * - default 2 + */ + u8 number_of_ap_slots_for_initiate_grant; + u8 reserved[3]; +} __packed; + +/* WMI_ENABLE_FIXED_SCHEDULING_CMDID */ +struct wmi_enable_fixed_scheduling_cmd { + __le32 reserved; +} __packed; + +/* WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID */ +struct wmi_enable_fixed_scheduling_complete_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID */ +struct wmi_set_multi_directed_omnis_config_cmd { + /* number of directed omnis at destination AP */ + u8 dest_ap_num_directed_omnis; + u8 reserved[3]; +} __packed; + +/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID */ +struct wmi_set_multi_directed_omnis_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_LONG_RANGE_CONFIG_CMDID */ +struct wmi_set_long_range_config_cmd { + __le32 reserved; +} __packed; + +/* WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID */ +struct wmi_set_long_range_config_complete_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; } __packed; /* WMI Events @@ -1039,19 +1244,22 @@ enum wmi_event_id { WMI_FW_READY_EVENTID = 0x1801, WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, WMI_ECHO_RSP_EVENTID = 0x1803, + /* deprecated */ WMI_FS_TUNE_DONE_EVENTID = 0x180A, + /* deprecated */ WMI_CORR_MEASURE_EVENTID = 0x180B, WMI_READ_RSSI_EVENTID = 0x180C, WMI_TEMP_SENSE_DONE_EVENTID = 0x180E, WMI_DC_CALIB_DONE_EVENTID = 0x180F, + /* deprecated */ WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811, + /* deprecated */ WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, - WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, - WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, - WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181A, + WMI_LO_POWER_CALIB_FROM_OTP_EVENTID = 0x1817, WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181D, + /* deprecated */ WMI_RF_RX_TEST_DONE_EVENTID = 0x181E, WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820, WMI_VRING_CFG_DONE_EVENTID = 0x1821, @@ -1062,11 +1270,6 @@ enum wmi_event_id { WMI_GET_SSID_EVENTID = 0x1828, WMI_GET_PCP_CHANNEL_EVENTID = 0x182A, WMI_SW_TX_COMPLETE_EVENTID = 0x182B, - WMI_READ_MAC_RXQ_EVENTID = 0x1830, - WMI_READ_MAC_TXQ_EVENTID = 0x1831, - WMI_WRITE_MAC_RXQ_EVENTID = 0x1832, - WMI_WRITE_MAC_TXQ_EVENTID = 0x1833, - WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834, WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, @@ -1077,8 +1280,12 @@ enum wmi_event_id { WMI_TX_MGMT_PACKET_EVENTID = 0x1841, WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID = 0x1842, WMI_LINK_MAINTAIN_CFG_READ_DONE_EVENTID = 0x1843, - WMI_OTP_READ_RESULT_EVENTID = 0x1856, + WMI_RF_XPM_READ_RESULT_EVENTID = 0x1856, + WMI_RF_XPM_WRITE_RESULT_EVENTID = 0x1857, WMI_LED_CFG_DONE_EVENTID = 0x1858, + WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID = 0x185C, + WMI_RF_PWR_ON_DELAY_RSP_EVENTID = 0x185D, + WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID = 0x185E, /* Performance monitoring events */ WMI_DATA_PORT_OPEN_EVENTID = 0x1860, WMI_WBE_LINK_DOWN_EVENTID = 0x1861, @@ -1107,14 +1314,6 @@ enum wmi_event_id { WMI_PCP_FACTOR_EVENTID = 0x191A, /* Power Save Configuration Events */ WMI_PS_DEV_PROFILE_CFG_EVENTID = 0x191C, - /* Not supported yet */ - WMI_PS_DEV_CFG_EVENTID = 0x191D, - /* Not supported yet */ - WMI_PS_DEV_CFG_READ_EVENTID = 0x191E, - /* Not supported yet */ - WMI_PS_MID_CFG_EVENTID = 0x191F, - /* Not supported yet */ - WMI_PS_MID_CFG_READ_EVENTID = 0x1920, WMI_RS_CFG_DONE_EVENTID = 0x1921, WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922, WMI_AOA_MEAS_EVENTID = 0x1923, @@ -1123,14 +1322,17 @@ enum wmi_event_id { WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931, WMI_SET_THERMAL_THROTTLING_CFG_EVENTID = 0x1940, WMI_GET_THERMAL_THROTTLING_CFG_EVENTID = 0x1941, + /* return the Power Save profile */ + WMI_PS_DEV_PROFILE_CFG_READ_EVENTID = 0x1942, WMI_TOF_SESSION_END_EVENTID = 0x1991, WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992, WMI_TOF_SET_LCR_EVENTID = 0x1993, WMI_TOF_SET_LCI_EVENTID = 0x1994, WMI_TOF_FTM_PER_DEST_RES_EVENTID = 0x1995, - WMI_TOF_CHANNEL_INFO_EVENTID = 0x1996, + WMI_TOF_CFG_RESPONDER_EVENTID = 0x1996, WMI_TOF_SET_TX_RX_OFFSET_EVENTID = 0x1997, WMI_TOF_GET_TX_RX_OFFSET_EVENTID = 0x1998, + WMI_TOF_CHANNEL_INFO_EVENTID = 0x1999, WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A0, WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A1, WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A2, @@ -1139,12 +1341,18 @@ enum wmi_event_id { WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, + WMI_SCHEDULING_SCHEME_EVENTID = 0x1A01, + WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID = 0x1A02, + WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID = 0x1A03, + WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID = 0x1A04, + WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID = 0x1A05, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, WMI_MAC_ADDR_RESP_EVENTID = 0x9003, WMI_FW_VER_EVENTID = 0x9004, WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID = 0x9005, + WMI_COMMAND_NOT_SUPPORTED_EVENTID = 0xFFFF, }; /* Events data structures */ @@ -1201,7 +1409,7 @@ struct wmi_fw_ver_event { __le32 bl_minor; __le32 bl_subminor; __le32 bl_build; - /* The number of entries in the FW capabilies array */ + /* The number of entries in the FW capabilities array */ u8 fw_capabilities_len; u8 reserved[3]; /* FW capabilities info @@ -1246,7 +1454,9 @@ struct wmi_get_rf_status_event { __le32 board_file_platform_type; /* board file version */ __le32 board_file_version; - __le32 reserved[2]; + /* enabled XIFs bit vector */ + __le32 enabled_xif_vector; + __le32 reserved; } __packed; /* WMI_GET_BASEBAND_TYPE_EVENTID */ @@ -1300,6 +1510,7 @@ struct wmi_ready_event { /* enum wmi_phy_capability */ u8 phy_capability; u8 numof_additional_mids; + /* rfc read calibration result. 5..15 */ u8 rfc_read_calib_result; u8 reserved[3]; } __packed; @@ -1580,7 +1791,7 @@ struct wmi_sw_tx_complete_event { u8 reserved[3]; } __packed; -/* WMI_CORR_MEASURE_EVENTID */ +/* WMI_CORR_MEASURE_EVENTID - deprecated */ struct wmi_corr_measure_event { /* signed */ __le32 i; @@ -1612,25 +1823,29 @@ struct wmi_rx_mgmt_info { __le16 stype; __le16 status; __le32 len; - /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */ + /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */ u8 qid; - /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */ + /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */ u8 mid; u8 cid; /* From Radio MNGR */ u8 channel; } __packed; -/* wmi_otp_read_write_cmd */ -struct wmi_otp_read_write_cmd { - __le32 addr; - __le32 size; - u8 values[0]; +/* EVENT: WMI_RF_XPM_READ_RESULT_EVENTID */ +struct wmi_rf_xpm_read_result_event { + /* enum wmi_fw_status_e - success=0 or fail=1 */ + u8 status; + u8 reserved[3]; + /* requested num_bytes of data */ + u8 data_bytes[0]; } __packed; -/* WMI_OTP_READ_RESULT_EVENTID */ -struct wmi_otp_read_result_event { - u8 payload[0]; +/* EVENT: WMI_RF_XPM_WRITE_RESULT_EVENTID */ +struct wmi_rf_xpm_write_result_event { + /* enum wmi_fw_status_e - success=0 or fail=1 */ + u8 status; + u8 reserved[3]; } __packed; /* WMI_TX_MGMT_PACKET_EVENTID */ @@ -1649,6 +1864,20 @@ struct wmi_echo_rsp_event { __le32 echoed_value; } __packed; +/* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */ +struct wmi_rf_pwr_on_delay_rsp_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID */ +struct wmi_set_high_power_table_params_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_TEMP_SENSE_DONE_EVENTID * * Measure MAC and radio temperatures @@ -1726,14 +1955,22 @@ struct wmi_led_cfg_cmd { u8 reserved; } __packed; +/* \WMI_SET_CONNECT_SNR_THR_CMDID */ +struct wmi_set_connect_snr_thr_cmd { + u8 enable; + u8 reserved; + /* 1/4 Db units */ + __le16 omni_snr_thr; + /* 1/4 Db units */ + __le16 direct_snr_thr; +} __packed; + /* WMI_LED_CFG_DONE_EVENTID */ struct wmi_led_cfg_done_event { /* led config status */ __le32 status; } __packed; -#define WMI_NUM_MCS (13) - /* Rate search parameters configuration per connection */ struct wmi_rs_cfg { /* The maximal allowed PER for each MCS @@ -1758,6 +1995,98 @@ struct wmi_rs_cfg { __le32 mcs_en_vec; } __packed; +/* Slot types */ +enum wmi_sched_scheme_slot_type { + WMI_SCHED_SLOT_SP = 0x0, + WMI_SCHED_SLOT_CBAP = 0x1, + WMI_SCHED_SLOT_IDLE = 0x2, + WMI_SCHED_SLOT_ANNOUNCE_NO_ACK = 0x3, + WMI_SCHED_SLOT_DISCOVERY = 0x4, +}; + +enum wmi_sched_scheme_slot_flags { + WMI_SCHED_SCHEME_SLOT_PERIODIC = 0x1, +}; + +struct wmi_sched_scheme_slot { + /* in microsecond */ + __le32 tbtt_offset; + /* wmi_sched_scheme_slot_flags */ + u8 flags; + /* wmi_sched_scheme_slot_type */ + u8 type; + /* in microsecond */ + __le16 duration; + /* frame_exchange_sequence_duration */ + __le16 tx_op; + /* time in microseconds between two consecutive slots + * relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set + */ + __le16 period; + /* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set + * number of times to repeat allocation + */ + u8 num_of_blocks; + /* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set + * every idle_period allocation will be idle + */ + u8 idle_period; + u8 src_aid; + u8 dest_aid; + __le32 reserved; +} __packed; + +enum wmi_sched_scheme_flags { + /* should not be set when clearing scheduling scheme */ + WMI_SCHED_SCHEME_ENABLE = 0x01, + WMI_SCHED_PROTECTED_SP = 0x02, + /* should be set only on first WMI fragment of scheme */ + WMI_SCHED_FIRST = 0x04, + /* should be set only on last WMI fragment of scheme */ + WMI_SCHED_LAST = 0x08, + WMI_SCHED_IMMEDIATE_START = 0x10, +}; + +enum wmi_sched_scheme_advertisment { + /* ESE is not advertised at all, STA has to be configured with WMI + * also + */ + WMI_ADVERTISE_ESE_DISABLED = 0x0, + WMI_ADVERTISE_ESE_IN_BEACON = 0x1, + WMI_ADVERTISE_ESE_IN_ANNOUNCE_FRAME = 0x2, +}; + +/* WMI_SCHEDULING_SCHEME_CMD */ +struct wmi_scheduling_scheme_cmd { + u8 serial_num; + /* wmi_sched_scheme_advertisment */ + u8 ese_advertisment; + /* wmi_sched_scheme_flags */ + __le16 flags; + u8 num_allocs; + u8 reserved[3]; + __le64 start_tbtt; + /* allocations list */ + struct wmi_sched_scheme_slot allocs[WMI_SCHED_MAX_ALLOCS_PER_CMD]; +} __packed; + +enum wmi_sched_scheme_failure_type { + WMI_SCHED_SCHEME_FAILURE_NO_ERROR = 0x00, + WMI_SCHED_SCHEME_FAILURE_OLD_START_TSF_ERR = 0x01, +}; + +/* WMI_SCHEDULING_SCHEME_EVENTID */ +struct wmi_scheduling_scheme_event { + /* wmi_fw_status_e */ + u8 status; + /* serial number given in command */ + u8 serial_num; + /* wmi_sched_scheme_failure_type */ + u8 failure_type; + /* alignment to 32b */ + u8 reserved[1]; +} __packed; + /* WMI_RS_CFG_CMDID */ struct wmi_rs_cfg_cmd { /* connection id */ @@ -1975,6 +2304,19 @@ enum wmi_ps_profile_type { WMI_PS_PROFILE_TYPE_LOW_LATENCY_PS = 0x03, }; +/* WMI_PS_DEV_PROFILE_CFG_READ_CMDID */ +struct wmi_ps_dev_profile_cfg_read_cmd { + /* reserved */ + __le32 reserved; +} __packed; + +/* WMI_PS_DEV_PROFILE_CFG_READ_EVENTID */ +struct wmi_ps_dev_profile_cfg_read_event { + /* wmi_ps_profile_type_e */ + u8 ps_profile; + u8 reserved[3]; +} __packed; + /* WMI_PS_DEV_PROFILE_CFG_CMDID * * Power save profile to be used by the device @@ -2023,157 +2365,6 @@ enum wmi_ps_d3_resp_policy { WMI_PS_D3_RESP_POLICY_APPROVED = 0x02, }; -/* Device common power save configurations */ -struct wmi_ps_dev_cfg { - /* lowest level of PS allowed while unassociated, enum wmi_ps_level_e - */ - u8 ps_unassoc_min_level; - /* lowest deep sleep clock level while nonassoc, enum - * wmi_ps_deep_sleep_clk_level_e - */ - u8 ps_unassoc_deep_sleep_min_level; - /* lowest level of PS allowed while associated, enum wmi_ps_level_e */ - u8 ps_assoc_min_level; - /* lowest deep sleep clock level while assoc, enum - * wmi_ps_deep_sleep_clk_level_e - */ - u8 ps_assoc_deep_sleep_min_level; - /* enum wmi_ps_deep_sleep_clk_level_e */ - u8 ps_assoc_low_latency_ds_min_level; - /* enum wmi_ps_d3_resp_policy_e */ - u8 ps_D3_response_policy; - /* BOOL */ - u8 ps_D3_pm_pme_enabled; - /* BOOL */ - u8 ps_halp_enable; - u8 ps_deep_sleep_enter_thresh_msec; - /* BOOL */ - u8 ps_voltage_scaling_en; -} __packed; - -/* WMI_PS_DEV_CFG_CMDID - * - * Configure common Power Save parameters of the device and all MIDs. - * - * Returned event: - * - WMI_PS_DEV_CFG_EVENTID - */ -struct wmi_ps_dev_cfg_cmd { - /* Device Power Save configuration to be applied */ - struct wmi_ps_dev_cfg ps_dev_cfg; - /* alignment to 32b */ - u8 reserved[2]; -} __packed; - -/* WMI_PS_DEV_CFG_EVENTID */ -struct wmi_ps_dev_cfg_event { - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; -} __packed; - -/* WMI_PS_DEV_CFG_READ_CMDID - * - * request to retrieve device Power Save configuration - * (WMI_PS_DEV_CFG_CMD params) - * - * Returned event: - * - WMI_PS_DEV_CFG_READ_EVENTID - */ -struct wmi_ps_dev_cfg_read_cmd { - __le32 reserved; -} __packed; - -/* WMI_PS_DEV_CFG_READ_EVENTID */ -struct wmi_ps_dev_cfg_read_event { - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; - /* Retrieved device Power Save configuration (WMI_PS_DEV_CFG_CMD - * params) - */ - struct wmi_ps_dev_cfg dev_ps_cfg; - /* alignment to 32b */ - u8 reserved[2]; -} __packed; - -/* Per Mac Power Save configurations */ -struct wmi_ps_mid_cfg { - /* Low power RX in BTI is enabled, BOOL */ - u8 beacon_lprx_enable; - /* Sync to sector ID enabled, BOOL */ - u8 beacon_sync_to_sectorId_enable; - /* Low power RX in DTI is enabled, BOOL */ - u8 frame_exchange_lprx_enable; - /* Sleep Cycle while in scheduled PS, 1-31 */ - u8 scheduled_sleep_cycle_pow2; - /* Stay Awake for k BIs every (sleep_cycle - k) BIs, 1-31 */ - u8 scheduled_num_of_awake_bis; - u8 am_to_traffic_load_thresh_mbp; - u8 traffic_to_am_load_thresh_mbps; - u8 traffic_to_am_num_of_no_traffic_bis; - /* BOOL */ - u8 continuous_traffic_psm; - __le16 no_traffic_to_min_usec; - __le16 no_traffic_to_max_usec; - __le16 snoozing_sleep_interval_milisec; - u8 max_no_data_awake_events; - /* Trigger WEB after k failed beacons */ - u8 num_of_failed_beacons_rx_to_trigger_web; - /* Trigger BF after k failed beacons */ - u8 num_of_failed_beacons_rx_to_trigger_bf; - /* Trigger SOB after k successful beacons */ - u8 num_of_successful_beacons_rx_to_trigger_sob; -} __packed; - -/* WMI_PS_MID_CFG_CMDID - * - * Configure Power Save parameters of a specific MID. - * These parameters are relevant for the specific BSS this MID belongs to. - * - * Returned event: - * - WMI_PS_MID_CFG_EVENTID - */ -struct wmi_ps_mid_cfg_cmd { - /* MAC ID */ - u8 mid; - /* mid PS configuration to be applied */ - struct wmi_ps_mid_cfg ps_mid_cfg; -} __packed; - -/* WMI_PS_MID_CFG_EVENTID */ -struct wmi_ps_mid_cfg_event { - /* MAC ID */ - u8 mid; - /* alignment to 32b */ - u8 reserved[3]; - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; -} __packed; - -/* WMI_PS_MID_CFG_READ_CMDID - * - * request to retrieve Power Save configuration of mid - * (WMI_PS_MID_CFG_CMD params) - * - * Returned event: - * - WMI_PS_MID_CFG_READ_EVENTID - */ -struct wmi_ps_mid_cfg_read_cmd { - /* MAC ID */ - u8 mid; - /* alignment to 32b */ - u8 reserved[3]; -} __packed; - -/* WMI_PS_MID_CFG_READ_EVENTID */ -struct wmi_ps_mid_cfg_read_event { - /* MAC ID */ - u8 mid; - /* Retrieved MID Power Save configuration(WMI_PS_MID_CFG_CMD params) */ - struct wmi_ps_mid_cfg mid_ps_cfg; - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; -} __packed; - #define WMI_AOA_MAX_DATA_SIZE (128) enum wmi_aoa_meas_status { @@ -2264,6 +2455,20 @@ struct wmi_tof_session_end_event { u8 reserved[3]; } __packed; +/* WMI_TOF_SET_LCI_EVENTID */ +struct wmi_tof_set_lci_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_TOF_SET_LCR_EVENTID */ +struct wmi_tof_set_lcr_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* Responder FTM Results */ struct wmi_responder_ftm_res { u8 t1[6]; @@ -2317,10 +2522,19 @@ struct wmi_tof_ftm_per_dest_res_event { __le32 tsf_sync; /* actual received ftm per burst */ u8 actual_ftm_per_burst; - u8 reserved0[7]; + /* Measurments are from RFs, defined by the mask */ + __le32 meas_rf_mask; + u8 reserved0[3]; struct wmi_responder_ftm_res responder_ftm_res[0]; } __packed; +/* WMI_TOF_CFG_RESPONDER_EVENTID */ +struct wmi_tof_cfg_responder_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + enum wmi_tof_channel_info_type { WMI_TOF_CHANNEL_INFO_AOA = 0x00, WMI_TOF_CHANNEL_INFO_LCI = 0x01, @@ -2357,12 +2571,15 @@ struct wmi_tof_set_tx_rx_offset_event { struct wmi_tof_get_tx_rx_offset_event { /* enum wmi_fw_status */ u8 status; - u8 reserved1[3]; + /* RF index used to read the offsets */ + u8 rf_index; + u8 reserved1[2]; /* TX delay offset */ __le32 tx_offset; /* RX delay offset */ __le32 rx_offset; - __le32 reserved2[2]; + /* Offset to strongest tap of CIR */ + __le32 precursor; } __packed; /* Result status codes for WMI commands */ @@ -2625,4 +2842,23 @@ struct wmi_prio_tx_sectors_set_default_cfg_event { u8 reserved[3]; } __packed; +/* WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID */ +struct wmi_set_silent_rssi_table_done_event { + /* enum wmi_silent_rssi_status */ + __le32 status; + /* enum wmi_silent_rssi_table */ + __le32 table; +} __packed; + +/* \WMI_COMMAND_NOT_SUPPORTED_EVENTID */ +struct wmi_command_not_supported_event { + /* device id */ + u8 mid; + u8 reserved0; + __le16 command_id; + /* for UT command only, otherwise reserved */ + __le16 command_subtype; + __le16 reserved1; +} __packed; + #endif /* __WILOCITY_WMI_H__ */ diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h index a3081433cc2b..9b56eb0c02fb 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h @@ -77,7 +77,7 @@ #define QMI_WLFW_FUNCTION_NAME_LEN_V01 128 #define QMI_WLFW_MAX_NUM_CE_V01 12 #define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32 -#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 512 +#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144 #define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128 #define QMI_WLFW_MAX_STR_LEN_V01 16 #define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24 @@ -483,7 +483,7 @@ struct wlfw_athdiag_read_resp_msg_v01 { u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01]; }; -#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 524 +#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156 extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[]; struct wlfw_athdiag_write_req_msg_v01 { @@ -493,7 +493,7 @@ struct wlfw_athdiag_write_req_msg_v01 { u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01]; }; -#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 531 +#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163 extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[]; struct wlfw_athdiag_write_resp_msg_v01 { diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 0333ab0fd926..34173b5e886f 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -201,6 +201,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */ unsigned long remaining_credit; struct timer_list credit_timeout; u64 credit_window_start; + bool rate_limited; /* Statistics */ struct xenvif_stats stats; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index e7bd63eb2876..60b26f32d31d 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -105,7 +105,11 @@ static int xenvif_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(napi); - xenvif_napi_schedule_or_enable_events(queue); + /* If the queue is rate-limited, it shall be + * rescheduled in the timer callback. + */ + if (likely(!queue->rate_limited)) + xenvif_napi_schedule_or_enable_events(queue); } return work_done; diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 1049c34e7d43..72ee1c305cc4 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -687,6 +687,7 @@ static void tx_add_credit(struct xenvif_queue *queue) max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */ queue->remaining_credit = min(max_credit, max_burst); + queue->rate_limited = false; } void xenvif_tx_credit_callback(unsigned long data) @@ -1184,8 +1185,10 @@ static bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size) msecs_to_jiffies(queue->credit_usec / 1000); /* Timer could already be pending in rare cases. */ - if (timer_pending(&queue->credit_timeout)) + if (timer_pending(&queue->credit_timeout)) { + queue->rate_limited = true; return true; + } /* Passed the point where we can replenish credit? */ if (time_after_eq64(now, next_credit)) { @@ -1200,6 +1203,7 @@ static bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size) mod_timer(&queue->credit_timeout, next_credit); queue->credit_window_start = next_credit; + queue->rate_limited = true; return true; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 85fa9da50779..df741c1c8e5f 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -531,7 +531,7 @@ static void ipa_wan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type) +static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache) { int retval; struct ipa_wan_msg *wan_msg; @@ -559,6 +559,25 @@ static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type) return retval; } + if (is_cache) { + mutex_lock(&ipa_ctx->ipa_cne_evt_lock); + + /* cache the cne event */ + memcpy(&ipa_ctx->ipa_cne_evt_req_cache[ + ipa_ctx->num_ipa_cne_evt_req].wan_msg, + wan_msg, + sizeof(struct ipa_wan_msg)); + + memcpy(&ipa_ctx->ipa_cne_evt_req_cache[ + ipa_ctx->num_ipa_cne_evt_req].msg_meta, + &msg_meta, + sizeof(struct ipa_msg_meta)); + + ipa_ctx->num_ipa_cne_evt_req++; + ipa_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE; + mutex_unlock(&ipa_ctx->ipa_cne_evt_lock); + } + return 0; } @@ -1328,21 +1347,21 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD: - retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD); + retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true); if (retval) { IPAERR("ipa_send_wan_msg failed: %d\n", retval); break; } break; case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL: - retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL); + retval = ipa_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true); if (retval) { IPAERR("ipa_send_wan_msg failed: %d\n", retval); break; } break; case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED: - retval = ipa_send_wan_msg(arg, WAN_EMBMS_CONNECT); + retval = ipa_send_wan_msg(arg, WAN_EMBMS_CONNECT, false); if (retval) { IPAERR("ipa_send_wan_msg failed: %d\n", retval); break; @@ -4165,6 +4184,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, mutex_init(&ipa_ctx->lock); mutex_init(&ipa_ctx->nat_mem.lock); + mutex_init(&ipa_ctx->ipa_cne_evt_lock); idr_init(&ipa_ctx->ipa_idr); spin_lock_init(&ipa_ctx->idr_lock); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index bfb1ce56412c..39d82fab325f 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -65,6 +65,8 @@ #define IPA_IPC_LOG_PAGES 50 +#define IPA_MAX_NUM_REQ_CACHE 10 + #define IPADBG(fmt, args...) \ do { \ pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\ @@ -996,6 +998,11 @@ struct ipacm_client_info { bool uplink; }; +struct ipa_cne_evt { + struct ipa_wan_msg wan_msg; + struct ipa_msg_meta msg_meta; +}; + /** * struct ipa_context - IPA context * @class: pointer to the struct class @@ -1197,6 +1204,9 @@ struct ipa_context { u32 ipa_rx_max_timeout_usec; u32 ipa_polling_iteration; bool ipa_uc_monitor_holb; + struct ipa_cne_evt ipa_cne_evt_req_cache[IPA_MAX_NUM_REQ_CACHE]; + int num_ipa_cne_evt_req; + struct mutex ipa_cne_evt_lock; }; /** diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 4cba8a7573bb..fd503f48f17c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -598,7 +598,7 @@ static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type) +static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache) { int retval; struct ipa_wan_msg *wan_msg; @@ -626,6 +626,25 @@ static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type) return retval; } + if (is_cache) { + mutex_lock(&ipa3_ctx->ipa_cne_evt_lock); + + /* cache the cne event */ + memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[ + ipa3_ctx->num_ipa_cne_evt_req].wan_msg, + wan_msg, + sizeof(struct ipa_wan_msg)); + + memcpy(&ipa3_ctx->ipa_cne_evt_req_cache[ + ipa3_ctx->num_ipa_cne_evt_req].msg_meta, + &msg_meta, + sizeof(struct ipa_msg_meta)); + + ipa3_ctx->num_ipa_cne_evt_req++; + ipa3_ctx->num_ipa_cne_evt_req %= IPA_MAX_NUM_REQ_CACHE; + mutex_unlock(&ipa3_ctx->ipa_cne_evt_lock); + } + return 0; } @@ -1603,21 +1622,21 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD: - retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD); + retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_ADD, true); if (retval) { IPAERR("ipa3_send_wan_msg failed: %d\n", retval); break; } break; case IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL: - retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL); + retval = ipa3_send_wan_msg(arg, WAN_UPSTREAM_ROUTE_DEL, true); if (retval) { IPAERR("ipa3_send_wan_msg failed: %d\n", retval); break; } break; case IPA_IOC_NOTIFY_WAN_EMBMS_CONNECTED: - retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT); + retval = ipa3_send_wan_msg(arg, WAN_EMBMS_CONNECT, false); if (retval) { IPAERR("ipa3_send_wan_msg failed: %d\n", retval); break; @@ -4820,6 +4839,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, mutex_init(&ipa3_ctx->lock); mutex_init(&ipa3_ctx->nat_mem.lock); mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex); + mutex_init(&ipa3_ctx->ipa_cne_evt_lock); idr_init(&ipa3_ctx->ipa_idr); spin_lock_init(&ipa3_ctx->idr_lock); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 7da78457f1b1..8ae714d4e7cc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -64,6 +64,8 @@ #define IPA_IPC_LOG_PAGES 50 +#define IPA_MAX_NUM_REQ_CACHE 10 + #define IPADBG(fmt, args...) \ do { \ pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\ @@ -1049,6 +1051,11 @@ struct ipa_dma_task_info { struct ipahal_imm_cmd_pyld *cmd_pyld; }; +struct ipa_cne_evt { + struct ipa_wan_msg wan_msg; + struct ipa_msg_meta msg_meta; +}; + /** * struct ipa3_context - IPA context * @class: pointer to the struct class @@ -1270,6 +1277,9 @@ struct ipa3_context { u32 ipa_tz_unlock_reg_num; struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg; struct ipa_dma_task_info dma_task_info; + struct ipa_cne_evt ipa_cne_evt_req_cache[IPA_MAX_NUM_REQ_CACHE]; + int num_ipa_cne_evt_req; + struct mutex ipa_cne_evt_lock; }; /** diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c index 49e0666d0c23..a9bcabfdb009 100644 --- a/drivers/platform/msm/usb_bam.c +++ b/drivers/platform/msm/usb_bam.c @@ -126,13 +126,13 @@ static char *bam_enable_strings[MAX_BAMS] = { * CI_CTRL & DWC3_CTRL shouldn't be used simultaneously * since both share the same prod & cons rm resourses */ -static enum ipa_client_type ipa_rm_resource_prod[MAX_BAMS] = { +static enum ipa_rm_resource_name ipa_rm_resource_prod[MAX_BAMS] = { [CI_CTRL] = IPA_RM_RESOURCE_USB_PROD, [HSIC_CTRL] = IPA_RM_RESOURCE_HSIC_PROD, [DWC3_CTRL] = IPA_RM_RESOURCE_USB_PROD, }; -static enum ipa_client_type ipa_rm_resource_cons[MAX_BAMS] = { +static enum ipa_rm_resource_name ipa_rm_resource_cons[MAX_BAMS] = { [CI_CTRL] = IPA_RM_RESOURCE_USB_CONS, [HSIC_CTRL] = IPA_RM_RESOURCE_HSIC_CONS, [DWC3_CTRL] = IPA_RM_RESOURCE_USB_CONS, @@ -1625,6 +1625,22 @@ static void usb_bam_ipa_create_resources(enum usb_ctrl cur_bam) } } +static void usb_bam_ipa_delete_resources(enum usb_ctrl cur_bam) +{ + int ret; + + ret = ipa_rm_delete_resource(ipa_rm_resource_prod[cur_bam]); + if (ret) + log_event_err("%s: Failed to delete USB_PROD resource\n", + __func__); + + ret = ipa_rm_delete_resource(ipa_rm_resource_cons[cur_bam]); + if (ret) + log_event_err("%s: Failed to delete USB_CONS resource\n", + __func__); + +} + static void wait_for_prod_granted(enum usb_ctrl cur_bam) { int ret; @@ -3401,6 +3417,7 @@ static int usb_bam_remove(struct platform_device *pdev) { struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev); + usb_bam_ipa_delete_resources(ctx->usb_bam_data->bam_type); usb_bam_unregister_panic_hdlr(); sps_deregister_bam_device(ctx->h_bam); destroy_workqueue(ctx->usb_bam_wq); diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index e97364cda236..4788053115e1 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1687,12 +1687,38 @@ static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) return 0; } +static int fg_configure_full_soc(struct fg_chip *chip, int bsoc) +{ + int rc; + u8 full_soc[2] = {0xFF, 0xFF}; + + /* + * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC + * needs to be updated to reflect the same. Write battery SOC to + * FULL_SOC and write a full value to MONOTONIC_SOC. + */ + rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, + (u8 *)&bsoc, 2, FG_IMA_ATOMIC); + if (rc < 0) { + pr_err("failed to write full_soc rc=%d\n", rc); + return rc; + } + + rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET, + full_soc, 2, FG_IMA_ATOMIC); + if (rc < 0) { + pr_err("failed to write monotonic_soc rc=%d\n", rc); + return rc; + } + + return 0; +} + #define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700 static int fg_charge_full_update(struct fg_chip *chip) { union power_supply_propval prop = {0, }; int rc, msoc, bsoc, recharge_soc, msoc_raw; - u8 full_soc[2] = {0xFF, 0xFF}; if (!chip->dt.hold_soc_while_full) return 0; @@ -1769,8 +1795,6 @@ static int fg_charge_full_update(struct fg_chip *chip) } } - chip->charge_full = false; - /* * Raise the recharge voltage so that VBAT_LT_RECHG signal * will be asserted soon as battery SOC had dropped below @@ -1783,35 +1807,23 @@ static int fg_charge_full_update(struct fg_chip *chip) rc); goto out; } - fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n", - msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc); - } else { - goto out; - } - if (!chip->charge_full) - goto out; + /* + * If charge_done is still set, wait for recharging or + * discharging to happen. + */ + if (chip->charge_done) + goto out; - /* - * During JEITA conditions, charge_full can happen early. FULL_SOC - * and MONOTONIC_SOC needs to be updated to reflect the same. Write - * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC. - */ - rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2, - FG_IMA_ATOMIC); - if (rc < 0) { - pr_err("failed to write full_soc rc=%d\n", rc); - goto out; - } + rc = fg_configure_full_soc(chip, bsoc); + if (rc < 0) + goto out; - rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET, - full_soc, 2, FG_IMA_ATOMIC); - if (rc < 0) { - pr_err("failed to write monotonic_soc rc=%d\n", rc); - goto out; + chip->charge_full = false; + fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n", + msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc); } - fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc); out: mutex_unlock(&chip->charge_full_lock); return rc; @@ -5126,6 +5138,29 @@ static int fg_gen3_remove(struct platform_device *pdev) return 0; } +static void fg_gen3_shutdown(struct platform_device *pdev) +{ + struct fg_chip *chip = dev_get_drvdata(&pdev->dev); + int rc, bsoc; + + if (chip->charge_full) { + rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc); + if (rc < 0) { + pr_err("Error in getting BATT_SOC, rc=%d\n", rc); + return; + } + + /* We need 2 most significant bytes here */ + bsoc = (u32)bsoc >> 16; + + rc = fg_configure_full_soc(chip, bsoc); + if (rc < 0) { + pr_err("Error in configuring full_soc, rc=%d\n", rc); + return; + } + } +} + static const struct of_device_id fg_gen3_match_table[] = { {.compatible = FG_GEN3_DEV_NAME}, {}, @@ -5140,6 +5175,7 @@ static struct platform_driver fg_gen3_driver = { }, .probe = fg_gen3_probe, .remove = fg_gen3_remove, + .shutdown = fg_gen3_shutdown, }; static int __init fg_gen3_init(void) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 6b942d9e5b74..1ed85dfc008d 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -329,12 +329,15 @@ qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj, struct qla_hw_data *ha = vha->hw; ssize_t rval = 0; + mutex_lock(&ha->optrom_mutex); + if (ha->optrom_state != QLA_SREADING) - return 0; + goto out; - mutex_lock(&ha->optrom_mutex); rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer, ha->optrom_region_size); + +out: mutex_unlock(&ha->optrom_mutex); return rval; @@ -349,14 +352,19 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj, struct device, kobj))); struct qla_hw_data *ha = vha->hw; - if (ha->optrom_state != QLA_SWRITING) + mutex_lock(&ha->optrom_mutex); + + if (ha->optrom_state != QLA_SWRITING) { + mutex_unlock(&ha->optrom_mutex); return -EINVAL; - if (off > ha->optrom_region_size) + } + if (off > ha->optrom_region_size) { + mutex_unlock(&ha->optrom_mutex); return -ERANGE; + } if (off + count > ha->optrom_region_size) count = ha->optrom_region_size - off; - mutex_lock(&ha->optrom_mutex); memcpy(&ha->optrom_buffer[off], buf, count); mutex_unlock(&ha->optrom_mutex); diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 5fe3c572628b..85c2b92f5474 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -570,7 +570,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, mutex_lock(&wpriv->glink_mutex); if (wpriv->ch) { - dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n", + dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n", __func__); ret = -EINVAL; goto done; @@ -579,7 +579,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, no_of_channels = pkt->no_of_channels; if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) { - dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n", + dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n", __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS); ret = -EINVAL; goto done; @@ -598,20 +598,20 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, size += WDSP_CH_CFG_SIZE; if (size > pkt_size) { - dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", __func__, size, pkt_size); ret = -EINVAL; goto err_ch_mem; } if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) { - dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n", __func__, ch_cfg->no_of_intents); ret = -EINVAL; goto err_ch_mem; } size += (sizeof(u32) * ch_cfg->no_of_intents); if (size > pkt_size) { - dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", __func__, size, pkt_size); ret = -EINVAL; goto err_ch_mem; @@ -746,7 +746,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf, } if (count > WDSP_MAX_READ_SIZE) { - dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n", + dev_info_ratelimited(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n", __func__, count); count = WDSP_MAX_READ_SIZE; } @@ -778,7 +778,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf, if (ret1) { mutex_unlock(&wpriv->rsp_mutex); - dev_err(wpriv->dev, "%s: copy_to_user failed %d\n", + dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n", __func__, ret); ret = -EFAULT; goto done; @@ -824,7 +824,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, if ((count < WDSP_WRITE_PKT_SIZE) || (count > WDSP_MAX_WRITE_SIZE)) { - dev_err(wpriv->dev, "%s: Invalid count = %zd\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid count = %zd\n", __func__, count); ret = -EINVAL; goto done; @@ -841,7 +841,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, ret = copy_from_user(tx_buf->buf, buf, count); if (ret) { - dev_err(wpriv->dev, "%s: copy_from_user failed %d\n", + dev_err_ratelimited(wpriv->dev, "%s: copy_from_user failed %d\n", __func__, ret); ret = -EFAULT; goto free_buf; @@ -852,7 +852,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, case WDSP_REG_PKT: if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE + WDSP_CH_CFG_SIZE)) { - dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", __func__, count); ret = -EINVAL; goto free_buf; @@ -861,7 +861,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, (struct wdsp_reg_pkt *)wpkt->payload, count); if (IS_ERR_VALUE(ret)) - dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n", + dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n", __func__, ret); vfree(tx_buf); break; @@ -871,7 +871,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, GLINK_LINK_STATE_UP), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { - dev_err(wpriv->dev, "%s: Link state wait timeout\n", + dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n", __func__); ret = -ETIMEDOUT; goto free_buf; @@ -881,7 +881,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, break; case WDSP_CMD_PKT: if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) { - dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", __func__, count); ret = -EINVAL; goto free_buf; @@ -889,7 +889,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, mutex_lock(&wpriv->glink_mutex); if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) { mutex_unlock(&wpriv->glink_mutex); - dev_err(wpriv->dev, "%s: Link state is Down\n", + dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n", __func__); ret = -ENETRESET; @@ -901,7 +901,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, sizeof(struct wdsp_cmd_pkt) + cpkt->payload_size; if (count < pkt_max_size) { - dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n", + dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n", __func__, count, pkt_max_size); ret = -EINVAL; goto free_buf; @@ -917,7 +917,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, } } if (!tx_buf->ch) { - dev_err(wpriv->dev, "%s: Failed to get glink channel\n", + dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n", __func__); ret = -EINVAL; goto free_buf; @@ -928,7 +928,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, GLINK_CONNECTED), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { - dev_err(wpriv->dev, "%s: glink channel %s is not in connected state %d\n", + dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n", __func__, tx_buf->ch->ch_cfg.name, tx_buf->ch->channel_state); ret = -ETIMEDOUT; @@ -940,7 +940,8 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, queue_work(wpriv->work_queue, &tx_buf->tx_work); break; default: - dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__); + dev_err_ratelimited(wpriv->dev, "%s: Invalid packet type\n", + __func__); ret = -EINVAL; vfree(tx_buf); break; @@ -986,6 +987,7 @@ static int wdsp_glink_open(struct inode *inode, struct file *file) goto err_wq; } + wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN; init_completion(&wpriv->rsp_complete); init_waitqueue_head(&wpriv->link_state_wait); mutex_init(&wpriv->rsp_mutex); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index a180c000e246..31d5d9c0e10b 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3965,6 +3965,8 @@ int iscsi_target_tx_thread(void *arg) { int ret = 0; struct iscsi_conn *conn = arg; + bool conn_freed = false; + /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. @@ -3990,12 +3992,14 @@ get_immediate: goto transport_err; ret = iscsit_handle_response_queue(conn); - if (ret == 1) + if (ret == 1) { goto get_immediate; - else if (ret == -ECONNRESET) + } else if (ret == -ECONNRESET) { + conn_freed = true; goto out; - else if (ret < 0) + } else if (ret < 0) { goto transport_err; + } } transport_err: @@ -4005,8 +4009,13 @@ transport_err: * responsible for cleaning up the early connection failure. */ if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN) - iscsit_take_action_for_connection_exit(conn); + iscsit_take_action_for_connection_exit(conn, &conn_freed); out: + if (!conn_freed) { + while (!kthread_should_stop()) { + msleep(100); + } + } return 0; } @@ -4105,6 +4114,7 @@ int iscsi_target_rx_thread(void *arg) u32 checksum = 0, digest = 0; struct iscsi_conn *conn = arg; struct kvec iov; + bool conn_freed = false; /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. @@ -4116,7 +4126,7 @@ int iscsi_target_rx_thread(void *arg) */ rc = wait_for_completion_interruptible(&conn->rx_login_comp); if (rc < 0 || iscsi_target_check_conn_state(conn)) - return 0; + goto out; if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { struct completion comp; @@ -4201,7 +4211,13 @@ int iscsi_target_rx_thread(void *arg) transport_err: if (!signal_pending(current)) atomic_set(&conn->transport_failed, 1); - iscsit_take_action_for_connection_exit(conn); + iscsit_take_action_for_connection_exit(conn, &conn_freed); +out: + if (!conn_freed) { + while (!kthread_should_stop()) { + msleep(100); + } + } return 0; } @@ -4575,8 +4591,11 @@ static void iscsit_logout_post_handler_closesession( * always sleep waiting for RX/TX thread shutdown to complete * within iscsit_close_connection(). */ - if (conn->conn_transport->transport_type == ISCSI_TCP) + if (conn->conn_transport->transport_type == ISCSI_TCP) { sleep = cmpxchg(&conn->tx_thread_active, true, false); + if (!sleep) + return; + } atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); @@ -4592,8 +4611,11 @@ static void iscsit_logout_post_handler_samecid( { int sleep = 1; - if (conn->conn_transport->transport_type == ISCSI_TCP) + if (conn->conn_transport->transport_type == ISCSI_TCP) { sleep = cmpxchg(&conn->tx_thread_active, true, false); + if (!sleep) + return; + } atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 210f6e4830e3..6c88fb021444 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -930,8 +930,10 @@ static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn) } } -void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) +void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn, bool *conn_freed) { + *conn_freed = false; + spin_lock_bh(&conn->state_lock); if (atomic_read(&conn->connection_exit)) { spin_unlock_bh(&conn->state_lock); @@ -942,6 +944,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) { spin_unlock_bh(&conn->state_lock); iscsit_close_connection(conn); + *conn_freed = true; return; } @@ -955,4 +958,5 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) spin_unlock_bh(&conn->state_lock); iscsit_handle_connection_cleanup(conn); + *conn_freed = true; } diff --git a/drivers/target/iscsi/iscsi_target_erl0.h b/drivers/target/iscsi/iscsi_target_erl0.h index a9e2f9497fb2..fbc1d84a63c3 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.h +++ b/drivers/target/iscsi/iscsi_target_erl0.h @@ -9,6 +9,6 @@ extern int iscsit_stop_time2retain_timer(struct iscsi_session *); extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *); extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int); extern void iscsit_fall_back_to_erl0(struct iscsi_session *); -extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *); +extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *, bool *); #endif /*** ISCSI_TARGET_ERL0_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 4a137b0ae3dc..b19edffa7d98 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -1436,5 +1436,9 @@ int iscsi_target_login_thread(void *arg) break; } + while (!kthread_should_stop()) { + msleep(100); + } + return 0; } diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 549a2bbbf4df..58c629aec73c 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -489,14 +489,60 @@ static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); -static bool iscsi_target_sk_state_check(struct sock *sk) +static bool __iscsi_target_sk_check_close(struct sock *sk) { if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { - pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE," + pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE," "returning FALSE\n"); - return false; + return true; } - return true; + return false; +} + +static bool iscsi_target_sk_check_close(struct iscsi_conn *conn) +{ + bool state = false; + + if (conn->sock) { + struct sock *sk = conn->sock->sk; + + read_lock_bh(&sk->sk_callback_lock); + state = (__iscsi_target_sk_check_close(sk) || + test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)); + read_unlock_bh(&sk->sk_callback_lock); + } + return state; +} + +static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag) +{ + bool state = false; + + if (conn->sock) { + struct sock *sk = conn->sock->sk; + + read_lock_bh(&sk->sk_callback_lock); + state = test_bit(flag, &conn->login_flags); + read_unlock_bh(&sk->sk_callback_lock); + } + return state; +} + +static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag) +{ + bool state = false; + + if (conn->sock) { + struct sock *sk = conn->sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + state = (__iscsi_target_sk_check_close(sk) || + test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)); + if (!state) + clear_bit(flag, &conn->login_flags); + write_unlock_bh(&sk->sk_callback_lock); + } + return state; } static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login) @@ -536,6 +582,20 @@ static void iscsi_target_do_login_rx(struct work_struct *work) pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", conn, current->comm, current->pid); + /* + * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready() + * before initial PDU processing in iscsi_target_start_negotiation() + * has completed, go ahead and retry until it's cleared. + * + * Otherwise if the TCP connection drops while this is occuring, + * iscsi_target_start_negotiation() will detect the failure, call + * cancel_delayed_work_sync(&conn->login_work), and cleanup the + * remaining iscsi connection resources from iscsi_np process context. + */ + if (iscsi_target_sk_check_flag(conn, LOGIN_FLAGS_INITIAL_PDU)) { + schedule_delayed_work(&conn->login_work, msecs_to_jiffies(10)); + return; + } spin_lock(&tpg->tpg_state_lock); state = (tpg->tpg_state == TPG_STATE_ACTIVE); @@ -543,26 +603,12 @@ static void iscsi_target_do_login_rx(struct work_struct *work) if (!state) { pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); - iscsi_target_restore_sock_callbacks(conn); - iscsi_target_login_drop(conn, login); - iscsit_deaccess_np(np, tpg, tpg_np); - return; + goto err; } - if (conn->sock) { - struct sock *sk = conn->sock->sk; - - read_lock_bh(&sk->sk_callback_lock); - state = iscsi_target_sk_state_check(sk); - read_unlock_bh(&sk->sk_callback_lock); - - if (!state) { - pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); - iscsi_target_restore_sock_callbacks(conn); - iscsi_target_login_drop(conn, login); - iscsit_deaccess_np(np, tpg, tpg_np); - return; - } + if (iscsi_target_sk_check_close(conn)) { + pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); + goto err; } conn->login_kworker = current; @@ -580,34 +626,29 @@ static void iscsi_target_do_login_rx(struct work_struct *work) flush_signals(current); conn->login_kworker = NULL; - if (rc < 0) { - iscsi_target_restore_sock_callbacks(conn); - iscsi_target_login_drop(conn, login); - iscsit_deaccess_np(np, tpg, tpg_np); - return; - } + if (rc < 0) + goto err; pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", conn, current->comm, current->pid); rc = iscsi_target_do_login(conn, login); if (rc < 0) { - iscsi_target_restore_sock_callbacks(conn); - iscsi_target_login_drop(conn, login); - iscsit_deaccess_np(np, tpg, tpg_np); + goto err; } else if (!rc) { - if (conn->sock) { - struct sock *sk = conn->sock->sk; - - write_lock_bh(&sk->sk_callback_lock); - clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags); - write_unlock_bh(&sk->sk_callback_lock); - } + if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE)) + goto err; } else if (rc == 1) { iscsi_target_nego_release(conn); iscsi_post_login_handler(np, conn, zero_tsih); iscsit_deaccess_np(np, tpg, tpg_np); } + return; + +err: + iscsi_target_restore_sock_callbacks(conn); + iscsi_target_login_drop(conn, login); + iscsit_deaccess_np(np, tpg, tpg_np); } static void iscsi_target_do_cleanup(struct work_struct *work) @@ -655,31 +696,54 @@ static void iscsi_target_sk_state_change(struct sock *sk) orig_state_change(sk); return; } + state = __iscsi_target_sk_check_close(sk); + pr_debug("__iscsi_target_sk_close_change: state: %d\n", state); + if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change" " conn: %p\n", conn); + if (state) + set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); write_unlock_bh(&sk->sk_callback_lock); orig_state_change(sk); return; } - if (test_and_set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { + if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n", conn); write_unlock_bh(&sk->sk_callback_lock); orig_state_change(sk); return; } + /* + * If the TCP connection has dropped, go ahead and set LOGIN_FLAGS_CLOSED, + * but only queue conn->login_work -> iscsi_target_do_login_rx() + * processing if LOGIN_FLAGS_INITIAL_PDU has already been cleared. + * + * When iscsi_target_do_login_rx() runs, iscsi_target_sk_check_close() + * will detect the dropped TCP connection from delayed workqueue context. + * + * If LOGIN_FLAGS_INITIAL_PDU is still set, which means the initial + * iscsi_target_start_negotiation() is running, iscsi_target_do_login() + * via iscsi_target_sk_check_close() or iscsi_target_start_negotiation() + * via iscsi_target_sk_check_and_clear() is responsible for detecting the + * dropped TCP connection in iscsi_np process context, and cleaning up + * the remaining iscsi connection resources. + */ + if (state) { + pr_debug("iscsi_target_sk_state_change got failed state\n"); + set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); + state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); + write_unlock_bh(&sk->sk_callback_lock); - state = iscsi_target_sk_state_check(sk); - write_unlock_bh(&sk->sk_callback_lock); - - pr_debug("iscsi_target_sk_state_change: state: %d\n", state); + orig_state_change(sk); - if (!state) { - pr_debug("iscsi_target_sk_state_change got failed state\n"); - schedule_delayed_work(&conn->login_cleanup_work, 0); + if (!state) + schedule_delayed_work(&conn->login_work, 0); return; } + write_unlock_bh(&sk->sk_callback_lock); + orig_state_change(sk); } @@ -944,6 +1008,15 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo if (iscsi_target_handle_csg_one(conn, login) < 0) return -1; if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { + /* + * Check to make sure the TCP connection has not + * dropped asynchronously while session reinstatement + * was occuring in this kthread context, before + * transitioning to full feature phase operation. + */ + if (iscsi_target_sk_check_close(conn)) + return -1; + login->tsih = conn->sess->tsih; login->login_complete = 1; iscsi_target_restore_sock_callbacks(conn); @@ -970,21 +1043,6 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo break; } - if (conn->sock) { - struct sock *sk = conn->sock->sk; - bool state; - - read_lock_bh(&sk->sk_callback_lock); - state = iscsi_target_sk_state_check(sk); - read_unlock_bh(&sk->sk_callback_lock); - - if (!state) { - pr_debug("iscsi_target_do_login() failed state for" - " conn: %p\n", conn); - return -1; - } - } - return 0; } @@ -1248,16 +1306,28 @@ int iscsi_target_start_negotiation( { int ret; + if (conn->sock) { + struct sock *sk = conn->sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + set_bit(LOGIN_FLAGS_READY, &conn->login_flags); + set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); + write_unlock_bh(&sk->sk_callback_lock); + } + /* + * If iscsi_target_do_login returns zero to signal more PDU + * exchanges are required to complete the login, go ahead and + * clear LOGIN_FLAGS_INITIAL_PDU but only if the TCP connection + * is still active. + * + * Otherwise if TCP connection dropped asynchronously, go ahead + * and perform connection cleanup now. + */ ret = iscsi_target_do_login(conn, login); - if (!ret) { - if (conn->sock) { - struct sock *sk = conn->sock->sk; + if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) + ret = -1; - write_lock_bh(&sk->sk_callback_lock); - set_bit(LOGIN_FLAGS_READY, &conn->login_flags); - write_unlock_bh(&sk->sk_callback_lock); - } - } else if (ret < 0) { + if (ret < 0) { cancel_delayed_work_sync(&conn->login_work); cancel_delayed_work_sync(&conn->login_cleanup_work); iscsi_target_restore_sock_callbacks(conn); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index f916d18ccb48..b070ddf1dc37 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -92,6 +92,11 @@ static int target_fabric_mappedlun_link( pr_err("Source se_lun->lun_se_dev does not exist\n"); return -EINVAL; } + if (lun->lun_shutdown) { + pr_err("Unable to create mappedlun symlink because" + " lun->lun_shutdown=true\n"); + return -EINVAL; + } se_tpg = lun->lun_tpg; nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 899c33b3c734..f69f4902dc07 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -673,6 +673,8 @@ void core_tpg_remove_lun( */ struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); + lun->lun_shutdown = true; + core_clear_lun_from_tpg(lun, tpg); /* * Wait for any active I/O references to percpu se_lun->lun_ref to @@ -694,6 +696,8 @@ void core_tpg_remove_lun( } if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_del_rcu(&lun->link); + + lun->lun_shutdown = false; mutex_unlock(&tpg->tpg_lun_mutex); percpu_ref_exit(&lun->lun_ref); diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 50d1619d7bc3..bca85bf2f7ec 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -4997,7 +4997,7 @@ static ssize_t __ref store_cc_enabled(struct kobject *kobj, hotplug_init_cpu_offlined(); mutex_lock(&core_control_mutex); update_offline_cores(cpus_offlined); - if (hotplug_enabled) { + if (hotplug_enabled && hotplug_task) { for_each_possible_cpu(cpu) { if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index ff93c343d41f..b07ba82fde34 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -3191,11 +3191,14 @@ int mdss_mdp_layer_atomic_validate_wfd(struct msm_fb_data_type *mfd, goto validate_failed; } + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); rc = mdss_mdp_wfd_setup(wfd, output_layer); if (rc) { pr_err("fail to prepare wfd = %d\n", rc); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); goto validate_failed; } + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); rc = mdss_mdp_layer_atomic_validate(mfd, file, commit); if (rc) { diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 8772bfc3415b..45ef9975caec 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -500,6 +500,8 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, lastoff = page_offset(page); bh = head = page_buffers(page); do { + if (lastoff + bh->b_size <= startoff) + goto next; if (buffer_uptodate(bh) || buffer_unwritten(bh)) { if (whence == SEEK_DATA) @@ -514,6 +516,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, unlock_page(page); goto out; } +next: lastoff += bh->b_size; bh = bh->b_this_page; } while (bh != head); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 34038e3598d5..74516efd874c 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1926,7 +1926,8 @@ retry: n_desc_blocks = o_desc_blocks + le16_to_cpu(es->s_reserved_gdt_blocks); n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb); - n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb); + n_blocks_count = (ext4_fsblk_t)n_group * + EXT4_BLOCKS_PER_GROUP(sb); n_group--; /* set to last group number */ } diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 6076c342dae6..5ac0b0bbb0ec 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -104,12 +104,19 @@ static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, { long err = -ENOTTY; struct file *lower_file; + const struct cred *saved_cred = NULL; + struct dentry *dentry = file->f_path.dentry; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); lower_file = sdcardfs_lower_file(file); /* XXX: use vfs_ioctl if/when VFS exports it */ if (!lower_file || !lower_file->f_op) goto out; + + /* save current_cred and override it */ + OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file))); + if (lower_file->f_op->unlocked_ioctl) err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); @@ -117,6 +124,7 @@ static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, if (!err) sdcardfs_copy_and_fix_attrs(file_inode(file), file_inode(lower_file)); + REVERT_CRED(saved_cred); out: return err; } @@ -127,15 +135,23 @@ static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd, { long err = -ENOTTY; struct file *lower_file; + const struct cred *saved_cred = NULL; + struct dentry *dentry = file->f_path.dentry; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); lower_file = sdcardfs_lower_file(file); /* XXX: use vfs_ioctl if/when VFS exports it */ if (!lower_file || !lower_file->f_op) goto out; + + /* save current_cred and override it */ + OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file))); + if (lower_file->f_op->compat_ioctl) err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); + REVERT_CRED(saved_cred); out: return err; } diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 1c1ff7e4faa4..021b1e9ff6cd 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -15,6 +15,8 @@ #include <net/net_namespace.h> #include <linux/sched/rt.h> +#include <asm/thread_info.h> + #ifdef CONFIG_SMP # define INIT_PUSHABLE_TASKS(tsk) \ .pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO), @@ -183,14 +185,21 @@ extern struct task_group root_task_group; # define INIT_KASAN(tsk) #endif +#ifdef CONFIG_THREAD_INFO_IN_TASK +# define INIT_TASK_TI(tsk) .thread_info = INIT_THREAD_INFO(tsk), +#else +# define INIT_TASK_TI(tsk) +#endif + /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ #define INIT_TASK(tsk) \ { \ + INIT_TASK_TI(tsk) \ .state = 0, \ - .stack = &init_thread_info, \ + .stack = init_stack, \ .usage = ATOMIC_INIT(2), \ .flags = PF_KTHREAD, \ .prio = MAX_PRIO-20, \ diff --git a/include/linux/kdb.h b/include/linux/kdb.h index a19bcf9e762e..410decacff8f 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -177,7 +177,7 @@ extern int kdb_get_kbd_char(void); static inline int kdb_process_cpu(const struct task_struct *p) { - unsigned int cpu = task_thread_info(p)->cpu; + unsigned int cpu = task_cpu(p); if (cpu > num_possible_cpus()) cpu = 0; return cpu; diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index e4937bbeae2c..33316a1ae98f 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -515,6 +515,10 @@ struct mm_struct { */ bool tlb_flush_pending; #endif +#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH + /* See flush_tlb_batched_pending() */ + bool tlb_flush_batched; +#endif struct uprobes_state uprobes_state; #ifdef CONFIG_X86_INTEL_MPX /* address of the bounds directory */ diff --git a/include/linux/restart_block.h b/include/linux/restart_block.h new file mode 100644 index 000000000000..0d905d8ec553 --- /dev/null +++ b/include/linux/restart_block.h @@ -0,0 +1,51 @@ +/* + * Common syscall restarting data + */ +#ifndef __LINUX_RESTART_BLOCK_H +#define __LINUX_RESTART_BLOCK_H + +#include <linux/compiler.h> +#include <linux/types.h> + +struct timespec; +struct compat_timespec; +struct pollfd; + +/* + * System call restart block. + */ +struct restart_block { + long (*fn)(struct restart_block *); + union { + /* For futex_wait and futex_wait_requeue_pi */ + struct { + u32 __user *uaddr; + u32 val; + u32 flags; + u32 bitset; + u64 time; + u32 __user *uaddr2; + } futex; + /* For nanosleep */ + struct { + clockid_t clockid; + struct timespec __user *rmtp; +#ifdef CONFIG_COMPAT + struct compat_timespec __user *compat_rmtp; +#endif + u64 expires; + } nanosleep; + /* For poll */ + struct { + struct pollfd __user *ufds; + int nfds; + int has_timeout; + unsigned long tv_sec; + unsigned long tv_nsec; + } poll; + }; +}; + +extern long do_no_restart_syscall(struct restart_block *parm); + +#endif /* __LINUX_RESTART_BLOCK_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index baf107821d9a..d1542e5cc81b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -882,6 +882,16 @@ struct signal_struct { #define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */ +#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \ + SIGNAL_STOP_CONTINUED) + +static inline void signal_set_stop_flags(struct signal_struct *sig, + unsigned int flags) +{ + WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP)); + sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags; +} + /* If true, all threads except ->group_exit_task have pending SIGKILL */ static inline int signal_group_exit(const struct signal_struct *sig) { @@ -1601,6 +1611,13 @@ struct tlbflush_unmap_batch { }; struct task_struct { +#ifdef CONFIG_THREAD_INFO_IN_TASK + /* + * For reasons of header soup (see current_thread_info()), this + * must be the first element of task_struct. + */ + struct thread_info thread_info; +#endif volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; atomic_t usage; @@ -1610,6 +1627,9 @@ struct task_struct { #ifdef CONFIG_SMP struct llist_node wake_entry; int on_cpu; +#ifdef CONFIG_THREAD_INFO_IN_TASK + unsigned int cpu; /* current CPU */ +#endif unsigned int wakee_flips; unsigned long wakee_flip_decay_ts; struct task_struct *last_wakee; @@ -2758,7 +2778,9 @@ extern void set_curr_task(int cpu, struct task_struct *p); void yield(void); union thread_union { +#ifndef CONFIG_THREAD_INFO_IN_TASK struct thread_info thread_info; +#endif unsigned long stack[THREAD_SIZE/sizeof(long)]; }; @@ -3154,10 +3176,34 @@ static inline void threadgroup_change_end(struct task_struct *tsk) cgroup_threadgroup_change_end(tsk); } -#ifndef __HAVE_THREAD_FUNCTIONS +#ifdef CONFIG_THREAD_INFO_IN_TASK + +static inline struct thread_info *task_thread_info(struct task_struct *task) +{ + return &task->thread_info; +} + +/* + * When accessing the stack of a non-current task that might exit, use + * try_get_task_stack() instead. task_stack_page will return a pointer + * that could get freed out from under you. + */ +static inline void *task_stack_page(const struct task_struct *task) +{ + return task->stack; +} + +#define setup_thread_stack(new,old) do { } while(0) + +static inline unsigned long *end_of_stack(const struct task_struct *task) +{ + return task->stack; +} + +#elif !defined(__HAVE_THREAD_FUNCTIONS) #define task_thread_info(task) ((struct thread_info *)(task)->stack) -#define task_stack_page(task) ((task)->stack) +#define task_stack_page(task) ((void *)(task)->stack) static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) { @@ -3184,6 +3230,14 @@ static inline unsigned long *end_of_stack(struct task_struct *p) } #endif + +static inline void *try_get_task_stack(struct task_struct *tsk) +{ + return task_stack_page(tsk); +} + +static inline void put_task_stack(struct task_struct *tsk) {} + #define task_stack_end_corrupted(task) \ (*(end_of_stack(task)) != STACK_END_MAGIC) @@ -3194,7 +3248,7 @@ static inline int object_is_on_stack(void *obj) return (obj >= stack) && (obj < (stack + THREAD_SIZE)); } -extern void thread_info_cache_init(void); +extern void thread_stack_cache_init(void); #ifdef CONFIG_DEBUG_STACK_USAGE static inline unsigned long stack_not_used(struct task_struct *p) @@ -3458,7 +3512,11 @@ static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume) static inline unsigned int task_cpu(const struct task_struct *p) { +#ifdef CONFIG_THREAD_INFO_IN_TASK + return p->cpu; +#else return task_thread_info(p)->cpu; +#endif } static inline int task_node(const struct task_struct *p) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b2c1ea2a4739..f276869a945e 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -402,7 +402,7 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port); static inline int uart_tx_stopped(struct uart_port *port) { struct tty_struct *tty = port->state->port.tty; - if (tty->stopped || port->hw_stopped) + if ((tty && tty->stopped) || port->hw_stopped) return 1; return 0; } diff --git a/include/linux/slab.h b/include/linux/slab.h index 4ef384b172e0..b4e739f04ee6 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -215,7 +215,7 @@ static inline const char *__check_heap_object(const void *ptr, * (PAGE_SIZE*2). Larger requests are passed to the page allocator. */ #define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1) -#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT) +#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1) #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 3 #endif @@ -228,7 +228,7 @@ static inline const char *__check_heap_object(const void *ptr, * be allocated from the same page. */ #define KMALLOC_SHIFT_HIGH PAGE_SHIFT -#define KMALLOC_SHIFT_MAX 30 +#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1) #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 3 #endif diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 4cf89517783a..8933ecc2bc9f 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -9,46 +9,17 @@ #include <linux/types.h> #include <linux/bug.h> +#include <linux/restart_block.h> -struct timespec; -struct compat_timespec; - +#ifdef CONFIG_THREAD_INFO_IN_TASK /* - * System call restart block. + * For CONFIG_THREAD_INFO_IN_TASK kernels we need <asm/current.h> for the + * definition of current, but for !CONFIG_THREAD_INFO_IN_TASK kernels, + * including <asm/current.h> can cause a circular dependency on some platforms. */ -struct restart_block { - long (*fn)(struct restart_block *); - union { - /* For futex_wait and futex_wait_requeue_pi */ - struct { - u32 __user *uaddr; - u32 val; - u32 flags; - u32 bitset; - u64 time; - u32 __user *uaddr2; - } futex; - /* For nanosleep */ - struct { - clockid_t clockid; - struct timespec __user *rmtp; -#ifdef CONFIG_COMPAT - struct compat_timespec __user *compat_rmtp; +#include <asm/current.h> +#define current_thread_info() ((struct thread_info *)current) #endif - u64 expires; - } nanosleep; - /* For poll */ - struct { - struct pollfd __user *ufds; - int nfds; - int has_timeout; - unsigned long tv_sec; - unsigned long tv_nsec; - } poll; - }; -}; - -extern long do_no_restart_syscall(struct restart_block *parm); #include <linux/bitops.h> #include <asm/thread_info.h> diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 0e32bc71245e..2e04fa5a5b58 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -311,6 +311,7 @@ enum { __WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */ __WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */ + __WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */ WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ @@ -408,7 +409,8 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, * Pointer to the allocated workqueue on success, %NULL on failure. */ #define alloc_ordered_workqueue(fmt, flags, args...) \ - alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args) + alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | \ + __WQ_ORDERED_EXPLICIT | (flags), 1, ##args) #define create_workqueue(name) \ alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name)) diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index e0f4109e64c6..c2aa73e5e6bb 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -556,7 +556,8 @@ iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends, memcpy(stream + lcp_len, ((char *) &iwe->u) + IW_EV_POINT_OFF, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); - memcpy(stream + point_len, extra, iwe->u.data.length); + if (iwe->u.data.length && extra) + memcpy(stream + point_len, extra, iwe->u.data.length); stream += event_len; } return stream; diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index ce13cf20f625..d33b17ba51d2 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -444,6 +444,8 @@ _sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) #define _sctp_walk_params(pos, chunk, end, member)\ for (pos.v = chunk->member;\ + (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\ + (void *)chunk + end) &&\ pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\ ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\ pos.v += WORD_ROUND(ntohs(pos.p->length))) @@ -454,6 +456,8 @@ _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length)) #define _sctp_walk_errors(err, chunk_hdr, end)\ for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ sizeof(sctp_chunkhdr_t));\ + ((void *)err + offsetof(sctp_errhdr_t, length) + sizeof(err->length) <=\ + (void *)chunk_hdr + end) &&\ (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\ ntohs(err->length) >= sizeof(sctp_errhdr_t); \ err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length)))) diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index e0efe3fcf739..fdda45f26f75 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -562,6 +562,7 @@ struct iscsi_conn { #define LOGIN_FLAGS_READ_ACTIVE 1 #define LOGIN_FLAGS_CLOSED 2 #define LOGIN_FLAGS_READY 4 +#define LOGIN_FLAGS_INITIAL_PDU 8 unsigned long login_flags; struct delayed_work login_work; struct delayed_work login_cleanup_work; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index ed66414b91f0..1adf8739980c 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -714,6 +714,7 @@ struct se_lun { #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; u32 lun_access; + bool lun_shutdown; u32 lun_index; /* RELATIVE TARGET PORT IDENTIFER */ diff --git a/init/Kconfig b/init/Kconfig index 7b8b4171ce00..1473414ec8fe 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -26,6 +26,16 @@ config IRQ_WORK config BUILDTIME_EXTABLE_SORT bool +config THREAD_INFO_IN_TASK + bool + help + Select this to move thread_info off the stack into task_struct. To + make this work, an arch will need to remove all thread_info fields + except flags and fix any runtime bugs. + + One subtle change that will be needed is to use try_get_task_stack() + and put_task_stack() in save_thread_stack_tsk() and get_wchan(). + menu "General setup" config BROKEN diff --git a/init/init_task.c b/init/init_task.c index ba0a7f362d9e..11f83be1fa79 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -22,5 +22,8 @@ EXPORT_SYMBOL(init_task); * Initial thread structure. Alignment of this is handled by a special * linker map entry. */ -union thread_union init_thread_union __init_task_data = - { INIT_THREAD_INFO(init_task) }; +union thread_union init_thread_union __init_task_data = { +#ifndef CONFIG_THREAD_INFO_IN_TASK + INIT_THREAD_INFO(init_task) +#endif +}; diff --git a/init/main.c b/init/main.c index 7d4532bff5da..8c72af285838 100644 --- a/init/main.c +++ b/init/main.c @@ -468,7 +468,7 @@ void __init __weak smp_setup_processor_id(void) } # if THREAD_SIZE >= PAGE_SIZE -void __init __weak thread_info_cache_init(void) +void __init __weak thread_stack_cache_init(void) { } #endif @@ -644,7 +644,7 @@ asmlinkage __visible void __init start_kernel(void) /* Should be run before the first non-init thread is created */ init_espfix_bsp(); #endif - thread_info_cache_init(); + thread_stack_cache_init(); cred_init(); fork_init(); proc_caches_init(); diff --git a/kernel/fork.c b/kernel/fork.c index fef4df444f47..07cd0d68ee02 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -148,18 +148,18 @@ static inline void free_task_struct(struct task_struct *tsk) } #endif -void __weak arch_release_thread_info(struct thread_info *ti) +void __weak arch_release_thread_stack(unsigned long *stack) { } -#ifndef CONFIG_ARCH_THREAD_INFO_ALLOCATOR +#ifndef CONFIG_ARCH_THREAD_STACK_ALLOCATOR /* * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a * kmemcache based allocator. */ # if THREAD_SIZE >= PAGE_SIZE -static struct thread_info *alloc_thread_info_node(struct task_struct *tsk, +static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node) { struct page *page = alloc_kmem_pages_node(node, THREADINFO_GFP, @@ -168,30 +168,32 @@ static struct thread_info *alloc_thread_info_node(struct task_struct *tsk, return page ? page_address(page) : NULL; } -static inline void free_thread_info(struct thread_info *ti) +static inline void free_thread_stack(unsigned long *stack) { - kasan_alloc_pages(virt_to_page(ti), THREAD_SIZE_ORDER); - free_kmem_pages((unsigned long)ti, THREAD_SIZE_ORDER); + struct page *page = virt_to_page(stack); + + kasan_alloc_pages(page, THREAD_SIZE_ORDER); + __free_kmem_pages(page, THREAD_SIZE_ORDER); } # else -static struct kmem_cache *thread_info_cache; +static struct kmem_cache *thread_stack_cache; -static struct thread_info *alloc_thread_info_node(struct task_struct *tsk, +static struct thread_info *alloc_thread_stack_node(struct task_struct *tsk, int node) { - return kmem_cache_alloc_node(thread_info_cache, THREADINFO_GFP, node); + return kmem_cache_alloc_node(thread_stack_cache, THREADINFO_GFP, node); } -static void free_thread_info(struct thread_info *ti) +static void free_stack(unsigned long *stack) { - kmem_cache_free(thread_info_cache, ti); + kmem_cache_free(thread_stack_cache, stack); } -void thread_info_cache_init(void) +void thread_stack_cache_init(void) { - thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE, + thread_stack_cache = kmem_cache_create("thread_stack", THREAD_SIZE, THREAD_SIZE, 0, NULL); - BUG_ON(thread_info_cache == NULL); + BUG_ON(thread_stack_cache == NULL); } # endif #endif @@ -214,9 +216,9 @@ struct kmem_cache *vm_area_cachep; /* SLAB cache for mm_struct structures (tsk->mm) */ static struct kmem_cache *mm_cachep; -static void account_kernel_stack(struct thread_info *ti, int account) +static void account_kernel_stack(unsigned long *stack, int account) { - struct zone *zone = page_zone(virt_to_page(ti)); + struct zone *zone = page_zone(virt_to_page(stack)); mod_zone_page_state(zone, NR_KERNEL_STACK, account); } @@ -224,8 +226,8 @@ static void account_kernel_stack(struct thread_info *ti, int account) void free_task(struct task_struct *tsk) { account_kernel_stack(tsk->stack, -1); - arch_release_thread_info(tsk->stack); - free_thread_info(tsk->stack); + arch_release_thread_stack(tsk->stack); + free_thread_stack(tsk->stack); rt_mutex_debug_task_free(tsk); ftrace_graph_exit_task(tsk); put_seccomp_filter(tsk); @@ -336,7 +338,7 @@ void set_task_stack_end_magic(struct task_struct *tsk) static struct task_struct *dup_task_struct(struct task_struct *orig, int node) { struct task_struct *tsk; - struct thread_info *ti; + unsigned long *stack; int err; if (node == NUMA_NO_NODE) @@ -345,15 +347,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) if (!tsk) return NULL; - ti = alloc_thread_info_node(tsk, node); - if (!ti) + stack = alloc_thread_stack_node(tsk, node); + if (!stack) goto free_tsk; err = arch_dup_task_struct(tsk, orig); if (err) - goto free_ti; + goto free_stack; - tsk->stack = ti; + tsk->stack = stack; #ifdef CONFIG_SECCOMP /* * We must handle setting up seccomp filters once we're under @@ -385,12 +387,12 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) tsk->task_frag.page = NULL; tsk->wake_q.next = NULL; - account_kernel_stack(ti, 1); + account_kernel_stack(stack, 1); return tsk; -free_ti: - free_thread_info(ti); +free_stack: + free_thread_stack(stack); free_tsk: free_task_struct(tsk); return NULL; diff --git a/kernel/kthread.c b/kernel/kthread.c index 698b8dec3074..d9b0be5c6a5f 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -65,7 +65,7 @@ static inline struct kthread *to_kthread(struct task_struct *k) static struct kthread *to_live_kthread(struct task_struct *k) { struct completion *vfork = ACCESS_ONCE(k->vfork_done); - if (likely(vfork)) + if (likely(vfork) && try_get_task_stack(k)) return __to_kthread(vfork); return NULL; } @@ -427,8 +427,10 @@ void kthread_unpark(struct task_struct *k) { struct kthread *kthread = to_live_kthread(k); - if (kthread) + if (kthread) { __kthread_unpark(k, kthread); + put_task_stack(k); + } } EXPORT_SYMBOL_GPL(kthread_unpark); @@ -457,6 +459,7 @@ int kthread_park(struct task_struct *k) wait_for_completion(&kthread->parked); } } + put_task_stack(k); ret = 0; } return ret; @@ -492,6 +495,7 @@ int kthread_stop(struct task_struct *k) __kthread_unpark(k, kthread); wake_up_process(k); wait_for_completion(&kthread->exited); + put_task_stack(k); } ret = k->exit_code; put_task_struct(k); diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c index 3ef3736002d8..9c951fade415 100644 --- a/kernel/locking/mutex-debug.c +++ b/kernel/locking/mutex-debug.c @@ -49,21 +49,21 @@ void debug_mutex_free_waiter(struct mutex_waiter *waiter) } void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, - struct thread_info *ti) + struct task_struct *task) { SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); /* Mark the current thread as blocked on the lock: */ - ti->task->blocked_on = waiter; + task->blocked_on = waiter; } void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, - struct thread_info *ti) + struct task_struct *task) { DEBUG_LOCKS_WARN_ON(list_empty(&waiter->list)); - DEBUG_LOCKS_WARN_ON(waiter->task != ti->task); - DEBUG_LOCKS_WARN_ON(ti->task->blocked_on != waiter); - ti->task->blocked_on = NULL; + DEBUG_LOCKS_WARN_ON(waiter->task != task); + DEBUG_LOCKS_WARN_ON(task->blocked_on != waiter); + task->blocked_on = NULL; list_del_init(&waiter->list); waiter->task = NULL; diff --git a/kernel/locking/mutex-debug.h b/kernel/locking/mutex-debug.h index 0799fd3e4cfa..d06ae3bb46c5 100644 --- a/kernel/locking/mutex-debug.h +++ b/kernel/locking/mutex-debug.h @@ -20,9 +20,9 @@ extern void debug_mutex_wake_waiter(struct mutex *lock, extern void debug_mutex_free_waiter(struct mutex_waiter *waiter); extern void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, - struct thread_info *ti); + struct task_struct *task); extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, - struct thread_info *ti); + struct task_struct *task); extern void debug_mutex_unlock(struct mutex *lock); extern void debug_mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key); diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 14b9cca36b05..bf5277ee11d3 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -549,7 +549,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, goto skip_wait; debug_mutex_lock_common(lock, &waiter); - debug_mutex_add_waiter(lock, &waiter, task_thread_info(task)); + debug_mutex_add_waiter(lock, &waiter, task); /* add waiting tasks to the end of the waitqueue (FIFO): */ list_add_tail(&waiter.list, &lock->wait_list); @@ -596,7 +596,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, } __set_task_state(task, TASK_RUNNING); - mutex_remove_waiter(lock, &waiter, current_thread_info()); + mutex_remove_waiter(lock, &waiter, task); /* set it to 0 if there are no waiters left: */ if (likely(list_empty(&lock->wait_list))) atomic_set(&lock->count, 0); @@ -617,7 +617,7 @@ skip_wait: return 0; err: - mutex_remove_waiter(lock, &waiter, task_thread_info(task)); + mutex_remove_waiter(lock, &waiter, task); spin_unlock_mutex(&lock->wait_lock, flags); debug_mutex_free_waiter(&waiter); mutex_release(&lock->dep_map, 1, ip); diff --git a/kernel/locking/mutex.h b/kernel/locking/mutex.h index 5cda397607f2..a68bae5e852a 100644 --- a/kernel/locking/mutex.h +++ b/kernel/locking/mutex.h @@ -13,7 +13,7 @@ do { spin_lock(lock); (void)(flags); } while (0) #define spin_unlock_mutex(lock, flags) \ do { spin_unlock(lock); (void)(flags); } while (0) -#define mutex_remove_waiter(lock, waiter, ti) \ +#define mutex_remove_waiter(lock, waiter, task) \ __list_del((waiter)->list.prev, (waiter)->list.next) #ifdef CONFIG_MUTEX_SPIN_ON_OWNER diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9fcb521fab0e..dca87791e9c1 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3180,9 +3180,8 @@ void show_regs_print_info(const char *log_lvl) { dump_stack_print_info(log_lvl); - printk("%stask: %p ti: %p task.ti: %p\n", - log_lvl, current, current_thread_info(), - task_thread_info(current)); + printk("%stask: %p task.stack: %p\n", + log_lvl, current, task_stack_page(current)); } #endif diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 67b7da81f8a2..33bf0c07e757 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1767,7 +1767,11 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) * per-task data have been completed by this moment. */ smp_wmb(); +#ifdef CONFIG_THREAD_INFO_IN_TASK + p->cpu = cpu; +#else task_thread_info(p)->cpu = cpu; +#endif p->wake_cpu = cpu; #endif } diff --git a/kernel/signal.c b/kernel/signal.c index b92a047ddc82..5d50ea899b6d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -346,7 +346,7 @@ static bool task_participate_group_stop(struct task_struct *task) * fresh group stop. Read comment in do_signal_stop() for details. */ if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) { - sig->flags = SIGNAL_STOP_STOPPED; + signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED); return true; } return false; @@ -845,7 +845,7 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force) * will take ->siglock, notice SIGNAL_CLD_MASK, and * notify its parent. See get_signal_to_deliver(). */ - signal->flags = why | SIGNAL_STOP_CONTINUED; + signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED); signal->group_stop_count = 0; signal->group_exit_code = 0; } diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 73c018d7df00..80b5dbfd187d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3669,8 +3669,12 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq, return -EINVAL; /* creating multiple pwqs breaks ordering guarantee */ - if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs))) - return -EINVAL; + if (!list_empty(&wq->pwqs)) { + if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT)) + return -EINVAL; + + wq->flags &= ~__WQ_ORDERED; + } ctx = apply_wqattrs_prepare(wq, attrs); @@ -3856,6 +3860,16 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, struct workqueue_struct *wq; struct pool_workqueue *pwq; + /* + * Unbound && max_active == 1 used to imply ordered, which is no + * longer the case on NUMA machines due to per-node pools. While + * alloc_ordered_workqueue() is the right way to create an ordered + * workqueue, keep the previous behavior to avoid subtle breakages + * on NUMA. + */ + if ((flags & WQ_UNBOUND) && max_active == 1) + flags |= __WQ_ORDERED; + /* see the comment above the definition of WQ_POWER_EFFICIENT */ if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient) flags |= WQ_UNBOUND; @@ -4044,13 +4058,14 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) struct pool_workqueue *pwq; /* disallow meddling with max_active for ordered workqueues */ - if (WARN_ON(wq->flags & __WQ_ORDERED)) + if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT)) return; max_active = wq_clamp_max_active(max_active, wq->flags, wq->name); mutex_lock(&wq->mutex); + wq->flags &= ~__WQ_ORDERED; wq->saved_max_active = max_active; for_each_pwq(pwq, wq) @@ -5178,7 +5193,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq) * attributes breaks ordering guarantee. Disallow exposing ordered * workqueues. */ - if (WARN_ON(wq->flags & __WQ_ORDERED)) + if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT)) return -EINVAL; wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6da96c4f98a5..23b74fd4e28f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -145,7 +145,7 @@ config DEBUG_INFO_REDUCED config DEBUG_INFO_SPLIT bool "Produce split debuginfo in .dwo files" - depends on DEBUG_INFO + depends on DEBUG_INFO && !FRV help Generate debug info into separate .dwo files. This significantly reduces the build directory size for builds with DEBUG_INFO, diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 192134b225ca..076eb03e316b 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -242,6 +242,7 @@ depot_stack_handle_t depot_save_stack(struct stack_trace *trace, */ alloc_flags &= ~GFP_ZONEMASK; alloc_flags &= (GFP_ATOMIC | GFP_KERNEL); + alloc_flags |= __GFP_NOWARN; page = alloc_pages(alloc_flags, STACK_ALLOC_ORDER); if (page) prealloc = page_address(page); diff --git a/mm/internal.h b/mm/internal.h index 46d27f378885..e17af58d2bf7 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -454,6 +454,7 @@ struct tlbflush_unmap_batch; #ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH void try_to_unmap_flush(void); void try_to_unmap_flush_dirty(void); +void flush_tlb_batched_pending(struct mm_struct *mm); #else static inline void try_to_unmap_flush(void) { @@ -461,6 +462,8 @@ static inline void try_to_unmap_flush(void) static inline void try_to_unmap_flush_dirty(void) { } - +static inline void flush_tlb_batched_pending(struct mm_struct *mm) +{ +} #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ #endif /* __MM_INTERNAL_H */ diff --git a/mm/memory.c b/mm/memory.c index 8689df9b09d5..d6e10c888541 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1127,6 +1127,7 @@ again: init_rss_vec(rss); start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl); pte = start_pte; + flush_tlb_batched_pending(mm); arch_enter_lazy_mmu_mode(); do { pte_t ptent = *pte; diff --git a/mm/mempool.c b/mm/mempool.c index 004d42b1dfaf..7924f4f58a6d 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -135,8 +135,8 @@ static void *remove_element(mempool_t *pool) void *element = pool->elements[--pool->curr_nr]; BUG_ON(pool->curr_nr < 0); - check_element(pool, element); kasan_unpoison_element(pool, element); + check_element(pool, element); return element; } diff --git a/mm/mprotect.c b/mm/mprotect.c index bddb2c75492d..b8849a3930a0 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -72,6 +72,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (!pte) return 0; + flush_tlb_batched_pending(vma->vm_mm); arch_enter_lazy_mmu_mode(); do { oldpte = *pte; diff --git a/mm/mremap.c b/mm/mremap.c index c25bc6268e46..fe7b7f65f4f4 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -135,6 +135,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, new_ptl = pte_lockptr(mm, new_pmd); if (new_ptl != old_ptl) spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING); + flush_tlb_batched_pending(vma->vm_mm); arch_enter_lazy_mmu_mode(); for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE, diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6759192e69de..bd4fb66c11c5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1579,14 +1579,14 @@ int move_freepages(struct zone *zone, #endif for (page = start_page; page <= end_page;) { - /* Make sure we are not inadvertently changing nodes */ - VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page); - if (!pfn_valid_within(page_to_pfn(page))) { page++; continue; } + /* Make sure we are not inadvertently changing nodes */ + VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page); + if (!PageBuddy(page)) { page++; continue; @@ -5953,8 +5953,8 @@ unsigned long free_reserved_area(void *start, void *end, int poison, char *s) } if (pages && s) - pr_info("Freeing %s memory: %ldK (%p - %p)\n", - s, pages << (PAGE_SHIFT - 10), start, end); + pr_info("Freeing %s memory: %ldK\n", + s, pages << (PAGE_SHIFT - 10)); return pages; } diff --git a/mm/rmap.c b/mm/rmap.c index 59489b3b1ac6..cbaf273b0f97 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -649,6 +649,13 @@ static void set_tlb_ubc_flush_pending(struct mm_struct *mm, tlb_ubc->flush_required = true; /* + * Ensure compiler does not re-order the setting of tlb_flush_batched + * before the PTE is cleared. + */ + barrier(); + mm->tlb_flush_batched = true; + + /* * If the PTE was dirty then it's best to assume it's writable. The * caller must use try_to_unmap_flush_dirty() or try_to_unmap_flush() * before the page is queued for IO. @@ -675,6 +682,35 @@ static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags) return should_defer; } + +/* + * Reclaim unmaps pages under the PTL but do not flush the TLB prior to + * releasing the PTL if TLB flushes are batched. It's possible for a parallel + * operation such as mprotect or munmap to race between reclaim unmapping + * the page and flushing the page. If this race occurs, it potentially allows + * access to data via a stale TLB entry. Tracking all mm's that have TLB + * batching in flight would be expensive during reclaim so instead track + * whether TLB batching occurred in the past and if so then do a flush here + * if required. This will cost one additional flush per reclaim cycle paid + * by the first operation at risk such as mprotect and mumap. + * + * This must be called under the PTL so that an access to tlb_flush_batched + * that is potentially a "reclaim vs mprotect/munmap/etc" race will synchronise + * via the PTL. + */ +void flush_tlb_batched_pending(struct mm_struct *mm) +{ + if (mm->tlb_flush_batched) { + flush_tlb_mm(mm); + + /* + * Do not allow the compiler to re-order the clearing of + * tlb_flush_batched before the tlb is flushed. + */ + barrier(); + mm->tlb_flush_batched = false; + } +} #else static void set_tlb_ubc_flush_pending(struct mm_struct *mm, struct page *page, bool writable) diff --git a/net/core/dev.c b/net/core/dev.c index 1ce844e41eaf..ccc6fe0e5ca1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2553,7 +2553,7 @@ static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) { if (tx_path) return skb->ip_summed != CHECKSUM_PARTIAL && - skb->ip_summed != CHECKSUM_NONE; + skb->ip_summed != CHECKSUM_UNNECESSARY; return skb->ip_summed == CHECKSUM_NONE; } diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index b94b1d293506..151e047ce072 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -28,6 +28,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; + ifr.ifr_name[IFNAMSIZ-1] = 0; error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex); if (error) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2ec5324a7ff7..5b3d611d8b5f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1742,7 +1742,8 @@ static int do_setlink(const struct sk_buff *skb, struct sockaddr *sa; int len; - len = sizeof(sa_family_t) + dev->addr_len; + len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len, + sizeof(*sa)); sa = kmalloc(len, GFP_KERNEL); if (!sa) { err = -ENOMEM; diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 1704948e6a12..f227f002c73d 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -1471,9 +1471,12 @@ int dccp_feat_init(struct sock *sk) * singleton values (which always leads to failure). * These settings can still (later) be overridden via sockopts. */ - if (ccid_get_builtin_ccids(&tx.val, &tx.len) || - ccid_get_builtin_ccids(&rx.val, &rx.len)) + if (ccid_get_builtin_ccids(&tx.val, &tx.len)) return -ENOBUFS; + if (ccid_get_builtin_ccids(&rx.val, &rx.len)) { + kfree(tx.val); + return -ENOBUFS; + } if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) || !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len)) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 6467bf392e1b..e217f17997a4 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -635,6 +635,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); + reqsk_put(req); return 0; drop_and_free: diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 3470ad1843bb..09a9ab65f4e1 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -376,6 +376,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); + reqsk_put(req); return 0; drop_and_free: diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 7c4c881a7187..ee94bd32d6dc 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -1320,13 +1320,14 @@ static struct pernet_operations fib_net_ops = { void __init ip_fib_init(void) { - rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL); - rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL); - rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL); + fib_trie_init(); register_pernet_subsys(&fib_net_ops); + register_netdevice_notifier(&fib_netdev_notifier); register_inetaddr_notifier(&fib_inetaddr_notifier); - fib_trie_init(); + rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL); + rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL); + rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL); } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 661bda968594..62e41d38da78 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -922,10 +922,12 @@ static int __ip_append_data(struct sock *sk, csummode = CHECKSUM_PARTIAL; cork->length += length; - if (((length > mtu) || (skb && skb_is_gso(skb))) && + if ((skb && skb_is_gso(skb)) || + (((length + (skb ? skb->len : fragheaderlen)) > mtu) && + (skb_queue_len(queue) <= 1) && (sk->sk_protocol == IPPROTO_UDP) && (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len && - (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx) { + (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx)) { err = ip_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, maxfraglen, flags); @@ -1241,6 +1243,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, return -EINVAL; if ((size + skb->len > mtu) && + (skb_queue_len(&sk->sk_write_queue) == 1) && (sk->sk_protocol == IPPROTO_UDP) && (rt->dst.dev->features & NETIF_F_UFO)) { if (skb->ip_summed != CHECKSUM_PARTIAL) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 2dc982b15df8..a2e1142145df 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -337,6 +337,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) treq = tcp_rsk(req); treq->rcv_isn = ntohl(th->seq) - 1; treq->snt_isn = cookie; + treq->txhash = net_tx_rndhash(); req->mss = mss; ireq->ir_num = ntohs(th->dest); ireq->ir_rmt_port = th->source; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 69d52fee247e..3dbff307218e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2504,8 +2504,8 @@ static inline void tcp_end_cwnd_reduction(struct sock *sk) struct tcp_sock *tp = tcp_sk(sk); /* Reset cwnd to ssthresh in CWR or Recovery (unless it's undone) */ - if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || - (tp->undo_marker && tp->snd_ssthresh < TCP_INFINITE_SSTHRESH)) { + if (tp->snd_ssthresh < TCP_INFINITE_SSTHRESH && + (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || tp->undo_marker)) { tp->snd_cwnd = tp->snd_ssthresh; tp->snd_cwnd_stamp = tcp_time_stamp; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2ca323b68efd..4e88f93f71c8 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3256,6 +3256,9 @@ int tcp_connect(struct sock *sk) struct sk_buff *buff; int err; + if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) + return -EHOSTUNREACH; /* Routing failure or similar. */ + tcp_connect_init(sk); if (unlikely(tp->repair)) { diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 4aef80d30fab..c1a84472cc0c 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -640,7 +640,8 @@ static void tcp_keepalive_timer (unsigned long data) goto death; } - if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) + if (!sock_flag(sk, SOCK_KEEPOPEN) || + ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT))) goto out; elapsed = keepalive_time_when(tp); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 254fcc7f1825..4d6f09c05a12 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -824,7 +824,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) if (is_udplite) /* UDP-Lite */ csum = udplite_csum(skb); - else if (sk->sk_no_check_tx) { /* UDP csum disabled */ + else if (sk->sk_no_check_tx && !skb_is_gso(skb)) { /* UDP csum off */ skb->ip_summed = CHECKSUM_NONE; goto send; diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 6396f1c80ae9..6dfc3daf7c21 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -231,7 +231,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, if (uh->check == 0) uh->check = CSUM_MANGLED_0; - skb->ip_summed = CHECKSUM_NONE; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* Fragment the skb. IP headers of the fragments are updated in * inet_gso_segment() diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 6177acdf60ac..635742a6d73f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -647,8 +647,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, *prevhdr = NEXTHDR_FRAGMENT; tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); if (!tmp_hdr) { - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGFAILS); err = -ENOMEM; goto fail; } @@ -767,8 +765,6 @@ slow_path: frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) + hroom + troom, GFP_ATOMIC); if (!frag) { - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGFAILS); err = -ENOMEM; goto fail; } @@ -1360,11 +1356,12 @@ emsgsize: */ cork->length += length; - if ((((length + fragheaderlen) > mtu) || - (skb && skb_is_gso(skb))) && + if ((skb && skb_is_gso(skb)) || + (((length + (skb ? skb->len : headersize)) > mtu) && + (skb_queue_len(queue) <= 1) && (sk->sk_protocol == IPPROTO_UDP) && (rt->dst.dev->features & NETIF_F_UFO) && - (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) { + (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk))) { err = ip6_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, exthdrlen, transhdrlen, mtu, flags, fl6); diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 8b56c5240429..f9f02581c4ca 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -78,7 +78,7 @@ EXPORT_SYMBOL(ipv6_select_ident); int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { - u16 offset = sizeof(struct ipv6hdr); + unsigned int offset = sizeof(struct ipv6hdr); unsigned int packet_len = skb_tail_pointer(skb) - skb_network_header(skb); int found_rhdr = 0; @@ -86,6 +86,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) while (offset <= packet_len) { struct ipv6_opt_hdr *exthdr; + unsigned int len; switch (**nexthdr) { @@ -111,7 +112,10 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + offset); - offset += ipv6_optlen(exthdr); + len = ipv6_optlen(exthdr); + if (len + offset >= IPV6_MAXPLEN) + return -EINVAL; + offset += len; *nexthdr = &exthdr->nexthdr; } diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 336843ca4e6b..7f3667635431 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -210,6 +210,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) treq->snt_synack.v64 = 0; treq->rcv_isn = ntohl(th->seq) - 1; treq->snt_isn = cookie; + treq->txhash = net_tx_rndhash(); /* * We need to lookup the dst_entry to get the correct window size. diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 01582966ffa0..2e3c12eeca07 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -86,7 +86,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, if (uh->check == 0) uh->check = CSUM_MANGLED_0; - skb->ip_summed = CHECKSUM_NONE; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* Check if there is enough headroom to insert fragment header. */ tnl_hlen = skb_tnl_header_len(skb); diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index ad58d2a6284e..6a2507f24b0f 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -577,8 +577,8 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, nla_for_each_nested(a, attr, rem) { int type = nla_type(a); - int maxlen = ovs_ct_attr_lens[type].maxlen; - int minlen = ovs_ct_attr_lens[type].minlen; + int maxlen; + int minlen; if (type > OVS_CT_ATTR_MAX) { OVS_NLERR(log, @@ -586,6 +586,9 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, type, OVS_CT_ATTR_MAX); return -EINVAL; } + + maxlen = ovs_ct_attr_lens[type].maxlen; + minlen = ovs_ct_attr_lens[type].minlen; if (nla_len(a) < minlen || nla_len(a) > maxlen) { OVS_NLERR(log, "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)", diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f8d6a0ca9c03..148ec130d99d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3622,14 +3622,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; if (val > INT_MAX) return -EINVAL; - po->tp_reserve = val; - return 0; + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_reserve = val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_LOSS: { @@ -4225,7 +4230,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, register_prot_hook(sk); } spin_unlock(&po->bind_lock); - if (closing && (po->tp_version > TPACKET_V2)) { + if (pg_vec && (po->tp_version > TPACKET_V2)) { /* Because we don't support block-based V3 on tx-ring */ if (!tx_ring) prb_shutdown_retire_blk_timer(po, rb_queue); diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index d05869646515..0915d448ba23 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -42,8 +42,8 @@ static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int return PTR_ERR(target); t->u.kernel.target = target; + memset(&par, 0, sizeof(par)); par.table = table; - par.entryinfo = NULL; par.target = target; par.targinfo = t->data; par.hook_mask = hook; diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 46881f329561..17c55e512de6 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -125,7 +125,7 @@ endif # ifeq ($(CONFIG_KASAN),y) _c_flags += $(if $(patsubst n%,, \ - $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)$(CONFIG_KASAN_SANITIZE_ALL)), \ + $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ $(CFLAGS_KASAN)) endif diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1f062aaa5414..9af294c72a4d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -654,7 +654,9 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) if (substream->ops->hw_free) result = substream->ops->hw_free(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); - pm_qos_remove_request(&substream->latency_pm_qos_req); + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); + return result; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 46a34039ecdc..5cab24f52825 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2233,6 +2233,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index cc7132d190b8..a01c781acdf1 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -2619,6 +2619,17 @@ static int msm_anlg_cdc_codec_enable_micbias(struct snd_soc_dapm_widget *w, return 0; } +static void set_compander_mode(void *handle, int val) +{ + struct sdm660_cdc_priv *handle_cdc = handle; + struct snd_soc_codec *codec = handle_cdc->codec; + + if (get_codec_version(handle_cdc) >= DIANGU) { + snd_soc_update_bits(codec, + MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, + 0x08, val); + }; +} static void update_clkdiv(void *handle, int val) { struct sdm660_cdc_priv *handle_cdc = handle; @@ -4636,6 +4647,7 @@ static int msm_anlg_cdc_probe(struct platform_device *pdev) BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier_mbhc); sdm660_cdc->dig_plat_data.handle = (void *) sdm660_cdc; + sdm660_cdc->dig_plat_data.set_compander_mode = set_compander_mode; sdm660_cdc->dig_plat_data.update_clkdiv = update_clkdiv; sdm660_cdc->dig_plat_data.get_cdc_version = get_cdc_version; sdm660_cdc->dig_plat_data.register_notifier = diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h index 9563565f36d2..d07d1bee4d6b 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h @@ -168,6 +168,7 @@ struct msm_dig_ctrl_data { struct msm_dig_ctrl_platform_data { void *handle; + void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); int (*register_notifier)(void *handle, diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index e64956aa2f40..25c318c6c4e1 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -214,60 +214,66 @@ static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec, int interp_n, int event) { struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec); + int comp_ch_bits_set = 0x03; dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n", __func__, event, interp_n, dig_cdc->comp_enabled[interp_n]); - /* compander is not enabled */ - if (!dig_cdc->comp_enabled[interp_n]) + /* compander is invalid */ + if (dig_cdc->comp_enabled[interp_n] != COMPANDER_1 && + dig_cdc->comp_enabled[interp_n]) { + dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__, + dig_cdc->comp_enabled[interp_n]); return 0; + } - switch (dig_cdc->comp_enabled[interp_n]) { - case COMPANDER_1: - if (SND_SOC_DAPM_EVENT_ON(event)) { - /* Enable Compander Clock */ - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL, - 1 << interp_n, 1 << interp_n); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50); - /* add sleep for compander to settle */ - usleep_range(1000, 1100); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0); + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* compander is not enabled */ + if (!dig_cdc->comp_enabled[interp_n]) { + dig_cdc->set_compander_mode(dig_cdc->handle, 0x00); + return 0; + }; + dig_cdc->set_compander_mode(dig_cdc->handle, 0x08); + /* Enable Compander Clock */ + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 1 << interp_n, 1 << interp_n); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50); + /* add sleep for compander to settle */ + usleep_range(1000, 1100); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0); - /* Enable Compander GPIO */ - if (dig_cdc->codec_hph_comp_gpio) - dig_cdc->codec_hph_comp_gpio(1, codec); - } else if (SND_SOC_DAPM_EVENT_OFF(event)) { - /* Disable Compander GPIO */ - if (dig_cdc->codec_hph_comp_gpio) - dig_cdc->codec_hph_comp_gpio(0, codec); + /* Enable Compander GPIO */ + if (dig_cdc->codec_hph_comp_gpio) + dig_cdc->codec_hph_comp_gpio(1, codec); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + /* Disable Compander GPIO */ + if (dig_cdc->codec_hph_comp_gpio) + dig_cdc->codec_hph_comp_gpio(0, codec); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 1 << interp_n, 0); + comp_ch_bits_set = snd_soc_read(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL); + if ((comp_ch_bits_set & 0x03) == 0x00) { snd_soc_update_bits(codec, MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL, - 1 << interp_n, 0); - snd_soc_update_bits(codec, + snd_soc_update_bits(codec, MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00); } - break; - default: - dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__, - dig_cdc->comp_enabled[interp_n]); - break; - }; - + } return 0; } @@ -2107,6 +2113,7 @@ static int msm_dig_cdc_probe(struct platform_device *pdev) msm_dig_cdc->dig_base, &msm_digital_regmap_config); msm_dig_cdc->update_clkdiv = pdata->update_clkdiv; + msm_dig_cdc->set_compander_mode = pdata->set_compander_mode; msm_dig_cdc->get_cdc_version = pdata->get_cdc_version; msm_dig_cdc->handle = pdata->handle; msm_dig_cdc->register_notifier = pdata->register_notifier; diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h index f0e7a9cf9228..11f36f99f1bd 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h @@ -49,6 +49,7 @@ struct msm_dig_priv { u32 mute_mask; int dapm_bias_off; void *handle; + void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); int (*register_notifier)(void *handle, @@ -58,6 +59,7 @@ struct msm_dig_priv { struct dig_ctrl_platform_data { void *handle; + void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); int (*register_notifier)(void *handle, diff --git a/sound/soc/msm/msm-pcm-hostless.c b/sound/soc/msm/msm-pcm-hostless.c index 57932433afe9..51b0a7208462 100644 --- a/sound/soc/msm/msm-pcm-hostless.c +++ b/sound/soc/msm/msm-pcm-hostless.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -25,7 +25,9 @@ static int msm_pcm_hostless_prepare(struct snd_pcm_substream *substream) pr_err("%s: invalid params\n", __func__); return -EINVAL; } - pm_qos_remove_request(&substream->latency_pm_qos_req); + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); + return 0; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0ba9dfb854b3..9694fe13021f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -203,11 +203,14 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n", be->dai_link->name, event, dir); - if (event == SND_SOC_DAPM_STREAM_STOP && be->dpcm[dir].users >= 1) { + + if ((event == SND_SOC_DAPM_STREAM_STOP) && + (be->dpcm[dir].users >= 1)) { pr_debug("%s Don't close BE \n", __func__); continue; } - snd_soc_dapm_stream_event(be, dir, event); + + snd_soc_dapm_stream_event(be, dir, event); } snd_soc_dapm_stream_event(fe, dir, event); |
