diff options
293 files changed, 3103 insertions, 1628 deletions
@@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 155 +SUBLEVEL = 158 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index f1ac9818b751..dbee1934dfc6 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -1,6 +1,5 @@ CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" -# CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index 323486d6ee83..561eac854cc3 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -1,6 +1,5 @@ CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" -# CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index 66191cd0447e..aa4f261b6508 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -1,6 +1,5 @@ CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" -# CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arm/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm/boot/dts/qcom/apq8016-sbc.dtsi index 6b8abbe68746..3011c88bd2f3 100644 --- a/arch/arm/boot/dts/qcom/apq8016-sbc.dtsi +++ b/arch/arm/boot/dts/qcom/apq8016-sbc.dtsi @@ -105,7 +105,7 @@ led@6 { label = "apq8016-sbc:blue:bt"; gpios = <&pm8916_mpps 3 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "bt"; + linux,default-trigger = "bluetooth-power"; default-state = "off"; }; }; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi index 8db5317f2106..7eb677d14814 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi @@ -108,7 +108,7 @@ qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; - qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>; + qcom,mdss-dsi-reset-sequence = <1 400>, <0 400>, <1 400>; qcom,mdss-dsi-tx-eot-append; qcom,mdss-dsi-post-init-delay = <1>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi index 8be20b4d2413..5a266cd9cf62 100644 --- a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi @@ -21,13 +21,6 @@ }; }; - aliases { - mhi_rmnet0 = &mhi_rmnet_0; - mhi_rmnet1 = &mhi_rmnet_1; - mhi_uci0 = &mhi_uci; - mhi0 = &mhi; - }; - gpio-leds { compatible = "gpio-leds"; @@ -146,52 +139,6 @@ gpio = <&tlmm 125 0>; }; - mhi_rmnet_0: qcom,mhi-rmnet@0 { - compatible = "qcom,mhi-rmnet"; - cell-index = <0>; - qcom,mhi = <&mhi>; - qcom,mhi-rx-channel = <101>; - qcom,mhi-tx-channel = <100>; - qcom,mhi-mru = <0x4000>; - status = "okay"; - }; - - mhi_rmnet_1: qcom,mhi-rmnet@1 { - compatible = "qcom,mhi-rmnet"; - cell-index = <1>; - qcom,mhi = <&mhi>; - qcom,mhi-rx-channel = <47>; - qcom,mhi-tx-channel = <46>; - qcom,mhi-mru = <0x4000>; - qcom,interface-name = "mhi_swip"; - status = "okay"; - }; - - mhi_uci: qcom,mhi-uci { - compatible = "qcom,mhi-uci"; - qcom,mhi-uci-channels = <0 0xffff>, - <1 0x1000>, - <2 0xffff>, - <3 0xffff>, - <10 0xffff>, - <11 0x1000>, - <14 0xffff>, - <15 0x1000>, - <16 0xffff>, - <17 0x1000>, - <18 0xffff>, - <19 0x1000>, - <22 0xffff>, - <23 0x1000>, - <24 0xffff>, - <25 0x1000>, - <32 0xffff>, - <33 0x1000>; - qcom,mhi-uci-ctrlchan = <18>; - qcom,mhi = <&mhi>; - status = "okay"; - }; - qcom,diagfwd-usb { compatible = "qcom,diagfwd-usb"; status = "okay"; @@ -362,85 +309,6 @@ /delete-property/ qcom,l1ss-supported; }; -&mdm3 { - pinctrl-names = "mdm_active", "mdm_suspend"; - pinctrl-0 = <&ap2mdm_active &mdm2ap_active>; - pinctrl-1 = <&ap2mdm_sleep &mdm2ap_sleep>; - interrupt-map = <0 &tlmm 108 0x3 - 1 &tlmm 106 0x3 - 2 &tlmm 112 0x3>; - qcom,mdm2ap-errfatal-gpio = <&tlmm 108 0x00>; - qcom,ap2mdm-errfatal-gpio = <&tlmm 109 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 106 0x00>; - qcom,ap2mdm-status-gpio = <&tlmm 107 0x00>; - qcom,ap2mdm-soft-reset-gpio = <&pm8994_mpps 2 0x00>; - qcom,ap2mdm-vddmin-gpio = <&tlmm 111 0x00>; - qcom,mdm2ap-vddmin-gpio = <&tlmm 112 0x00>; - qcom,mdm-auto-boot; - qcom,ignore-ssr-failure; - qcom,mdm-link-info = "0302_02.01.00"; - qcom,mdm-statusline-not-a-powersource; - qcom,mdm-userspace-handle-shutdown; - qcom,pil-force-shutdown; - qcom,shutdown-timeout-ms = <30000>; - qcom,reset-time-ms = <16203>; - status = "okay"; -}; - -&mhi { - qcom,mhi-address-window = <0x0 0x80000000 0x1 0xffffffff>; - qcom,pci-dev_id = <0x0302>; - qcom,pci-domain = <2>; - qcom,pci-bus = <1>; - qcom,pci-slot = <0>; - esoc-names = "mdm"; - esoc-0 = <&mdm3>; - qcom,msm-bus,name = "mhi"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <100 512 0 0>, - <100 512 1200000000 650000000>; - mhi-chan-cfg-0 = <0x0 0x80 0x2 0x92>; - mhi-chan-cfg-1 = <0x1 0x80 0x2 0xa2>; - mhi-chan-cfg-2 = <0x2 0x80 0x1 0x91>; - mhi-chan-cfg-3 = <0x3 0x80 0x1 0xa1>; - mhi-chan-cfg-4 = <0x4 0x80 0x2 0x92>; - mhi-chan-cfg-5 = <0x5 0x80 0x2 0xa2>; - mhi-chan-cfg-6 = <0x6 0xa 0x2 0x92>; - mhi-chan-cfg-7 = <0x7 0xa 0x2 0xa2>; - mhi-chan-cfg-10 = <0xa 0x80 0x1 0x92>; - mhi-chan-cfg-11 = <0xb 0x80 0x1 0xa2>; - mhi-chan-cfg-14 = <0xe 0x40 0x1 0x92>; - mhi-chan-cfg-15 = <0xf 0x40 0x1 0xa2>; - mhi-chan-cfg-16 = <0x10 0x40 0x1 0x92>; - mhi-chan-cfg-17 = <0x11 0x40 0x1 0xa2>; - mhi-chan-cfg-18 = <0x12 0x40 0x1 0x92>; - mhi-chan-cfg-19 = <0x13 0x40 0x1 0xa2>; - mhi-chan-cfg-20 = <0x14 0xa 0x2 0x92>; - mhi-chan-cfg-21 = <0x15 0xa 0x2 0xa2>; - mhi-chan-cfg-22 = <0x16 0x40 0x2 0x92>; - mhi-chan-cfg-23 = <0x17 0x40 0x2 0xa2>; - mhi-chan-cfg-24 = <0x18 0xa 0x1 0x91>; - mhi-chan-cfg-25 = <0x19 0xa 0x1 0xa1>; - mhi-chan-cfg-32 = <0x20 0x80 0x2 0x92>; - mhi-chan-cfg-33 = <0x21 0x80 0x2 0xa2>; - mhi-chan-cfg-34 = <0x22 0x80 0x2 0x92>; - mhi-chan-cfg-35 = <0x23 0x80 0x2 0xa2>; - mhi-chan-cfg-46 = <0x2e 0x80 0x2 0x412>; - mhi-chan-cfg-47 = <0x2f 0x80 0x3 0x422>; - mhi-chan-cfg-100 = <0x64 0x80 0x4 0x652>; - mhi-chan-cfg-101 = <0x65 0x80 0x5 0x762>; - mhi-event-rings = <6>; - mhi-event-cfg-0 = <0x80 0x0 0x1 0 1 0x11>; - mhi-event-cfg-1 = <0x80 0x1 0x1 0 1 0x11>; - mhi-event-cfg-2 = <0x80 0x2 0x5 0 2 0x11>; - mhi-event-cfg-3 = <0x100 0x3 0x1 47 1 0x48>; - mhi-event-cfg-4 = <0x100 0x4 0x1 100 1 0x69>; - mhi-event-cfg-5 = <0x100 0x5 0x1 101 1 0x68>; - status = "okay"; -}; - &pm8994_gpios { gpio@c700 { /* GPIO 8 - WLAN_EN */ qcom,mode = <1>; /* Digital output*/ diff --git a/arch/arm/boot/dts/qcom/sdm455.dtsi b/arch/arm/boot/dts/qcom/sdm455.dtsi index e37416783b30..1f3e406f5f12 100644 --- a/arch/arm/boot/dts/qcom/sdm455.dtsi +++ b/arch/arm/boot/dts/qcom/sdm455.dtsi @@ -43,3 +43,17 @@ /delete-property/ qcom,mdss-dest-scaler-lut-off; }; }; + +&soc { + /delete-node/ devfreq_memlat_0; + devfreq_memlat_0: qcom,arm-memlat-mon-0 { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&memlat_cpu0>; + qcom,core-dev-table = + < 1113600 762 >, + < 1344000 2086 >, + < 1670400 4943 >, + < 2016000 5163 >; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi index fd109450ad81..6b409c091527 100644 --- a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -193,6 +193,13 @@ qcom,panel-roi-alignment = <2 2 4 2 1080 2>; }; +&dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &pm660l_pwm_4 { qcom,dtest-line = <2>; /* DTEST2 */ qcom,dtest-output = <2>; /* OUTPUT PWM */ diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi index 4e3ebd445814..16cfbd0e97bc 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,7 @@ #include "dsi-panel-truly-1080p-video.dtsi" #include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" #include "dsi-panel-sharp-split-link-wuxga-video.dtsi" +#include "dsi-panel-lgd-incell-sw49106-fhd-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -243,3 +244,13 @@ qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; }; + +&dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1b 08 09 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x30>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi index fd7cc8a7c5c2..19d1cb4d2210 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -216,3 +216,10 @@ &dsi_rm67195_amoled_fhd_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; }; + +&dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index 384e24d221c4..82e80891e05d 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -366,16 +366,6 @@ gpio-key,wakeup; debounce-interval = <15>; }; - - home { - label = "home"; - gpios = <&pm660_gpios 11 0x1>; - linux,input-type = <1>; - linux,code = <102>; - gpio-key,wakeup; - debounce-interval = <15>; - }; - }; hbtp { diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 5b97aea1c013..eaab6fd3e1aa 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -75,6 +75,52 @@ }; }; + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + /* SDC pin type */ sdc1_clk_on: sdc1_clk_on { config { diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index e8f32390704e..27bc0cebfc2a 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -2412,6 +2412,10 @@ "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", "MAX"; + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + resets = <&clock_gcc GCC_UFS_BCR>; reset-names = "core_reset"; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts index 40595275b63a..3434514df69c 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts @@ -170,9 +170,7 @@ }; wlan { subsys-name = "AR6320"; - interrupts = <0 43 0>; - interrupt-names = "state-irq"; - type = "virtual"; + type = "native"; offset = <512>; }; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi.dts index 5f622b41fecd..ae2ec051d50e 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi.dts @@ -20,14 +20,29 @@ qcom,msm-id = <246 0x0>; }; +&ion { + /delete-node/ qcom,ion-heap@25; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + audio_heap: qcom,ion-heap@28 { + reg = <28>; + memory-region = <&ion_audio>; + qcom,ion-heap-type = "CARVEOUT"; + }; +}; + &reserved_memory { pmem_shared: pmem_shared_region@1154ca000 { reg = <0x1 0x154ca000 0x0 0x154ca000>; label = "pmem_shared_mem"; }; - ion_system: ion_system_region@12a994000 { - reg = <0x1 0x2a994000 0x0 0x154ca000>; - label = "ion_system_mem"; + ion_audio: ion_audio_region { + reg = <0 0xf0000000 0 0x00400000>; + label = "ion_audio_mem"; }; }; diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index b3490c1c49d1..4187f69f6630 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -261,7 +261,6 @@ CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y -CONFIG_USB_CHIPIDEA_ULPI=y CONFIG_USB_SERIAL=m CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_FTDI_SIO=m @@ -288,7 +287,6 @@ CONFIG_USB_G_NCM=m CONFIG_USB_GADGETFS=m CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m -CONFIG_USB_ULPI_BUS=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h index 7da5503c0591..e08d15184056 100644 --- a/arch/arm/include/asm/arch_gicv3.h +++ b/arch/arm/include/asm/arch_gicv3.h @@ -117,6 +117,7 @@ static inline u32 gic_read_iar(void) u32 irqstat; asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat)); + dsb(sy); return irqstat; } diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 30a7228eaceb..9440b320a8a3 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -12,6 +12,7 @@ #include <asm/unistd.h> #include <asm/ftrace.h> #include <asm/unwind.h> +#include <asm/memory.h> #ifdef CONFIG_NEED_RET_TO_USER #include <mach/entry-macro.S> @@ -35,6 +36,9 @@ ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) disable_irq_notrace @ disable interrupts + ldr r2, [tsk, #TI_ADDR_LIMIT] + cmp r2, #TASK_SIZE + blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK bne fast_work_pending @@ -61,6 +65,9 @@ ret_fast_syscall: UNWIND(.cantunwind ) str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 disable_irq_notrace @ disable interrupts + ldr r2, [tsk, #TI_ADDR_LIMIT] + cmp r2, #TASK_SIZE + blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK beq no_work_pending @@ -93,6 +100,9 @@ ENTRY(ret_to_user) ret_slow_syscall: disable_irq_notrace @ disable interrupts ENTRY(ret_to_user_from_irq) + ldr r2, [tsk, #TI_ADDR_LIMIT] + cmp r2, #TASK_SIZE + blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne slow_work_pending diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 7b8f2141427b..304e68408f9c 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -14,6 +14,7 @@ #include <linux/uaccess.h> #include <linux/tracehook.h> #include <linux/uprobes.h> +#include <linux/syscalls.h> #include <asm/elf.h> #include <asm/cacheflush.h> @@ -631,3 +632,9 @@ struct page *get_signal_page(void) return page; } + +/* Defer to generic check */ +asmlinkage void addr_limit_check_failed(void) +{ + addr_limit_user_check(); +} diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index c169cc3049aa..e8adb428dddb 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -260,6 +260,7 @@ static int __init exynos_pmu_irq_init(struct device_node *node, NULL); if (!domain) { iounmap(pmu_base_addr); + pmu_base_addr = NULL; return -ENOMEM; } diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c index a129aae72602..909bb2493781 100644 --- a/arch/arm/mach-hisi/hotplug.c +++ b/arch/arm/mach-hisi/hotplug.c @@ -148,13 +148,20 @@ static int hi3xxx_hotplug_init(void) struct device_node *node; node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); - if (node) { - ctrl_base = of_iomap(node, 0); - id = HI3620_CTRL; - return 0; + if (!node) { + id = ERROR_CTRL; + return -ENOENT; } - id = ERROR_CTRL; - return -ENOENT; + + ctrl_base = of_iomap(node, 0); + of_node_put(node); + if (!ctrl_base) { + id = ERROR_CTRL; + return -ENOMEM; + } + + id = HI3620_CTRL; + return 0; } void hi3xxx_set_cpu(int cpu, bool enable) @@ -173,11 +180,15 @@ static bool hix5hd2_hotplug_init(void) struct device_node *np; np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl"); - if (np) { - ctrl_base = of_iomap(np, 0); - return true; - } - return false; + if (!np) + return false; + + ctrl_base = of_iomap(np, 0); + of_node_put(np); + if (!ctrl_base) + return false; + + return true; } void hix5hd2_set_cpu(int cpu, bool enable) @@ -219,10 +230,10 @@ void hip01_set_cpu(int cpu, bool enable) if (!ctrl_base) { np = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl"); - if (np) - ctrl_base = of_iomap(np, 0); - else - BUG(); + BUG_ON(!np); + ctrl_base = of_iomap(np, 0); + of_node_put(np); + BUG_ON(!ctrl_base); } if (enable) { diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 475fa24aba88..0f624b69649d 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -511,7 +511,6 @@ CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y -CONFIG_IOMMU_TESTS=y CONFIG_MSM_PASR=y CONFIG_MSM_SMEM=y CONFIG_QPNP_HAPTIC=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 49416b31c24b..39a9b67d36b0 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -519,7 +519,6 @@ CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y -CONFIG_IOMMU_TESTS=y CONFIG_MSM_PASR=y CONFIG_MSM_SMEM=y CONFIG_QPNP_HAPTIC=y diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index db6d058ab0f3..70c11c25d3e4 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -120,6 +120,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NEED_RESCHED 1 #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */ +#define TIF_FSCHECK 4 /* Check FS is USER_DS on return */ #define TIF_NOHZ 7 #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 @@ -141,10 +142,12 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_FSCHECK (1 << TIF_FSCHECK) #define _TIF_32BIT (1 << TIF_32BIT) #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ - _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE) + _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ + _TIF_FSCHECK) #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index d39d8bde42d7..d0919bcb1953 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -73,6 +73,9 @@ static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; + /* On user-mode return, check fs is correct */ + set_thread_flag(TIF_FSCHECK); + /* * Enable/disable UAO so that copy_to_user() etc can access * kernel memory with the unprivileged instructions. diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index a8eafdbc7cb8..0bed9a899850 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -25,6 +25,7 @@ #include <linux/uaccess.h> #include <linux/tracehook.h> #include <linux/ratelimit.h> +#include <linux/syscalls.h> #include <asm/debug-monitors.h> #include <asm/elf.h> @@ -402,6 +403,9 @@ static void do_signal(struct pt_regs *regs) asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int thread_flags) { + /* Check valid user FS if needed */ + addr_limit_user_check(); + if (thread_flags & _TIF_SIGPENDING) do_signal(regs); diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index 8755d618e116..961c393c0f55 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -44,6 +44,7 @@ static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; static void ath79_restart(char *command) { + local_irq_disable(); ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); for (;;) if (cpu_wait) diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index d113c8ded6e2..6df3a4ea77fc 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -349,6 +349,7 @@ static int __init octeon_ehci_device_init(void) return 0; pd = of_find_device_by_node(ehci_node); + of_node_put(ehci_node); if (!pd) return 0; @@ -411,6 +412,7 @@ static int __init octeon_ohci_device_init(void) return 0; pd = of_find_device_by_node(ohci_node); + of_node_put(ohci_node); if (!pd) return 0; diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 75fa296836fc..ab1df19b0957 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -141,14 +141,14 @@ static inline void * phys_to_virt(unsigned long address) /* * ISA I/O bus memory addresses are 1:1 with the physical address. */ -static inline unsigned long isa_virt_to_bus(volatile void * address) +static inline unsigned long isa_virt_to_bus(volatile void *address) { - return (unsigned long)address - PAGE_OFFSET; + return virt_to_phys(address); } -static inline void * isa_bus_to_virt(unsigned long address) +static inline void *isa_bus_to_virt(unsigned long address) { - return (void *)(address + PAGE_OFFSET); + return phys_to_virt(address); } #define isa_page_to_bus page_to_phys diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h index 4eee221b0cf0..d2be8e4f7a35 100644 --- a/arch/mips/include/asm/mach-ath79/ath79.h +++ b/arch/mips/include/asm/mach-ath79/ath79.h @@ -133,6 +133,7 @@ static inline u32 ath79_pll_rr(unsigned reg) static inline void ath79_reset_wr(unsigned reg, u32 val) { __raw_writel(val, ath79_reset_base + reg); + (void) __raw_readl(ath79_reset_base + reg); /* flush */ } static inline u32 ath79_reset_rr(unsigned reg) diff --git a/arch/mips/jz4740/Platform b/arch/mips/jz4740/Platform index 28448d358c10..a2a5a85ea1f9 100644 --- a/arch/mips/jz4740/Platform +++ b/arch/mips/jz4740/Platform @@ -1,4 +1,4 @@ platform-$(CONFIG_MACH_INGENIC) += jz4740/ cflags-$(CONFIG_MACH_INGENIC) += -I$(srctree)/arch/mips/include/asm/mach-jz4740 load-$(CONFIG_MACH_INGENIC) += 0xffffffff80010000 -zload-$(CONFIG_MACH_INGENIC) += 0xffffffff80600000 +zload-$(CONFIG_MACH_INGENIC) += 0xffffffff81000000 diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 9684a0d22d97..dd92540fbc75 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -117,7 +117,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs, *regs = current_pt_regs(); unsigned long childksp; - p->set_child_tid = p->clear_child_tid = NULL; childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32; diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 3fcc833b316d..cf2882fd0c17 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -14,12 +14,14 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/irqchip/mips-gic.h> +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/timekeeper_internal.h> #include <asm/abi.h> +#include <asm/page.h> #include <asm/vdso.h> /* Kernel-provided data used by the VDSO. */ @@ -128,12 +130,30 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vvar_size = gic_size + PAGE_SIZE; size = vvar_size + image->size; + /* + * Find a region that's large enough for us to perform the + * colour-matching alignment below. + */ + if (cpu_has_dc_aliases) + size += shm_align_mask + 1; + base = get_unmapped_area(NULL, 0, size, 0, 0); if (IS_ERR_VALUE(base)) { ret = base; goto out; } + /* + * If we suffer from dcache aliasing, ensure that the VDSO data page + * mapping is coloured the same as the kernel's mapping of that memory. + * This ensures that when the kernel updates the VDSO data userland + * will observe it without requiring cache invalidations. + */ + if (cpu_has_dc_aliases) { + base = __ALIGN_MASK(base, shm_align_mask); + base += ((unsigned long)&vdso_data - gic_size) & shm_align_mask; + } + data_addr = base + gic_size; vdso_addr = data_addr + PAGE_SIZE; diff --git a/arch/mips/loongson64/common/cs5536/cs5536_ohci.c b/arch/mips/loongson64/common/cs5536/cs5536_ohci.c index f7c905e50dc4..92dc6bafc127 100644 --- a/arch/mips/loongson64/common/cs5536/cs5536_ohci.c +++ b/arch/mips/loongson64/common/cs5536/cs5536_ohci.c @@ -138,7 +138,7 @@ u32 pci_ohci_read_reg(int reg) break; case PCI_OHCI_INT_REG: _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo); - if ((lo & 0x00000f00) == CS5536_USB_INTR) + if (((lo >> PIC_YSEL_LOW_USB_SHIFT) & 0xf) == CS5536_USB_INTR) conf_data = 1; break; default: diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index d66a61efb143..52cb3e09d172 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -712,7 +712,8 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) { /* Catch bad driver code */ - BUG_ON(size == 0); + if (WARN_ON(size == 0)) + return; preempt_disable(); if (cpu_has_inclusive_pcaches) { @@ -745,7 +746,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) { /* Catch bad driver code */ - BUG_ON(size == 0); + if (WARN_ON(size == 0)) + return; preempt_disable(); if (cpu_has_inclusive_pcaches) { diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 7095dfe7666b..962372143fda 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -152,8 +152,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, top_of_kernel_stack = sp; - p->set_child_tid = p->clear_child_tid = NULL; - /* Locate userspace context on stack... */ sp -= STACK_FRAME_OVERHEAD; /* redzone */ sp -= sizeof(struct pt_regs); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index e48826aa314c..b40606051efe 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -371,7 +371,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) /* Closed or other error drop */ if (rc != OPAL_SUCCESS && rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) { - written = total_len; + written += total_len; break; } if (rc == OPAL_SUCCESS) { diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index f5313a78e5d6..9795e52bab3d 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -311,7 +311,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) int len, error_log_length; error_log_length = 8 + rtas_error_extended_log_length(h); - len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX); + len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX); memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX); memcpy(global_mce_data_buf, h, len); errhdr = (struct rtas_error_log *)global_mce_data_buf; diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c index 3f165d972a0e..994fe73c2ed0 100644 --- a/arch/powerpc/sysdev/mpic_msgr.c +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -196,7 +196,7 @@ static int mpic_msgr_probe(struct platform_device *dev) /* IO map the message register block. */ of_address_to_resource(np, 0, &rsrc); - msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); + msgr_block_addr = ioremap(rsrc.start, resource_size(&rsrc)); if (!msgr_block_addr) { dev_err(&dev->dev, "Failed to iomap MPIC message registers"); return -EFAULT; diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index 16c5998b9792..4254c477e8e0 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -26,7 +26,7 @@ */ ENTRY(memset) ltgr %r4,%r4 - bzr %r14 + jz .Lmemset_exit ltgr %r3,%r3 jnz .Lmemset_fill aghi %r4,-1 @@ -41,12 +41,13 @@ ENTRY(memset) .Lmemset_clear_rest: larl %r3,.Lmemset_xc ex %r4,0(%r3) +.Lmemset_exit: BR_EX %r14 .Lmemset_fill: stc %r3,0(%r2) cghi %r4,1 lgr %r1,%r2 - ber %r14 + je .Lmemset_fill_exit aghi %r4,-2 srlg %r3,%r4,8 ltgr %r3,%r3 @@ -58,6 +59,7 @@ ENTRY(memset) .Lmemset_fill_rest: larl %r3,.Lmemset_mvc ex %r4,0(%r3) +.Lmemset_fill_exit: BR_EX %r14 .Lmemset_xc: xc 0(1,%r1),0(%r1) @@ -71,7 +73,7 @@ ENTRY(memset) */ ENTRY(memcpy) ltgr %r4,%r4 - bzr %r14 + jz .Lmemcpy_exit aghi %r4,-1 srlg %r5,%r4,8 ltgr %r5,%r5 @@ -80,6 +82,7 @@ ENTRY(memcpy) .Lmemcpy_rest: larl %r5,.Lmemcpy_mvc ex %r4,0(%r5) +.Lmemcpy_exit: BR_EX %r14 .Lmemcpy_loop: mvc 0(256,%r1),0(%r3) diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 071582a3b5c0..a9e501303e15 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -22,6 +22,7 @@ #include <linux/user-return-notifier.h> #include <linux/nospec.h> #include <linux/uprobes.h> +#include <linux/syscalls.h> #include <asm/desc.h> #include <asm/traps.h> @@ -273,6 +274,8 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs) struct thread_info *ti = pt_regs_to_thread_info(regs); u32 cached_flags; + addr_limit_user_check(); + if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled())) local_irq_disable(); diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index 5c686382d84b..095dbc25122a 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_PGTABLE_3LEVEL_H #define _ASM_X86_PGTABLE_3LEVEL_H +#include <asm/atomic64_32.h> + /* * Intel Physical Address Extension (PAE) Mode - three-level page * tables on PPro+ CPUs. @@ -142,10 +144,7 @@ static inline pte_t native_ptep_get_and_clear(pte_t *ptep) { pte_t res; - /* xchg acts as a barrier before the setting of the high bits */ - res.pte_low = xchg(&ptep->pte_low, 0); - res.pte_high = ptep->pte_high; - ptep->pte_high = 0; + res.pte = (pteval_t)atomic64_xchg((atomic64_t *)ptep, 0); return res; } diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 68a55273ce0f..a67d7f210b7c 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -385,7 +385,7 @@ static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) static inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot) { - phys_addr_t pfn = page_nr << PAGE_SHIFT; + phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT; pfn ^= protnone_mask(pgprot_val(pgprot)); pfn &= PHYSICAL_PUD_PAGE_MASK; return __pud(pfn | massage_pgprot(pgprot)); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 337c52192278..440a948c4feb 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -104,6 +104,8 @@ struct cpuinfo_x86 { __u8 x86_phys_bits; /* CPUID returned core id bits: */ __u8 x86_coreid_bits; + + __u8 x86_cache_bits; /* Max extended CPUID function supported: */ __u32 extended_cpuid_level; /* Maximum supported CPUID level, -1=no CPUID: */ @@ -174,7 +176,7 @@ extern void cpu_detect(struct cpuinfo_x86 *c); static inline unsigned long long l1tf_pfn_limit(void) { - return BIT_ULL(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT); + return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT); } extern void early_cpu_init(void); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index e8d453732823..c14f699f5c36 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -111,6 +111,7 @@ struct thread_info { #define TIF_SYSCALL_TRACEPOINT 28 /* syscall tracepoint instrumentation */ #define TIF_ADDR32 29 /* 32-bit address space on 64 bits */ #define TIF_X32 30 /* 32-bit native x86-64 binary */ +#define TIF_FSCHECK 31 /* Check FS is USER_DS on return */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -135,6 +136,7 @@ struct thread_info { #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_ADDR32 (1 << TIF_ADDR32) #define _TIF_X32 (1 << TIF_X32) +#define _TIF_FSCHECK (1 << TIF_FSCHECK) /* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ @@ -145,7 +147,7 @@ struct thread_info { /* work to do on any return to user space */ #define _TIF_ALLWORK_MASK \ ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT | \ - _TIF_NOHZ) + _TIF_NOHZ | _TIF_FSCHECK) /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 6a07c05956a6..8857f6f4daa9 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -30,7 +30,12 @@ #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) +static inline void set_fs(mm_segment_t fs) +{ + current_thread_info()->addr_limit = fs; + /* On user-mode return, check fs is correct */ + set_thread_flag(TIF_FSCHECK); +} #define segment_eq(a, b) ((a).seg == (b).seg) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index b9e6b60df148..621bc6561189 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -634,6 +634,46 @@ void x86_spec_ctrl_setup_ap(void) #undef pr_fmt #define pr_fmt(fmt) "L1TF: " fmt + +/* + * These CPUs all support 44bits physical address space internally in the + * cache but CPUID can report a smaller number of physical address bits. + * + * The L1TF mitigation uses the top most address bit for the inversion of + * non present PTEs. When the installed memory reaches into the top most + * address bit due to memory holes, which has been observed on machines + * which report 36bits physical address bits and have 32G RAM installed, + * then the mitigation range check in l1tf_select_mitigation() triggers. + * This is a false positive because the mitigation is still possible due to + * the fact that the cache uses 44bit internally. Use the cache bits + * instead of the reported physical bits and adjust them on the affected + * machines to 44bit if the reported bits are less than 44. + */ +static void override_cache_bits(struct cpuinfo_x86 *c) +{ + if (c->x86 != 6) + return; + + switch (c->x86_model) { + case INTEL_FAM6_NEHALEM: + case INTEL_FAM6_WESTMERE: + case INTEL_FAM6_SANDYBRIDGE: + case INTEL_FAM6_IVYBRIDGE: + case INTEL_FAM6_HASWELL_CORE: + case INTEL_FAM6_HASWELL_ULT: + case INTEL_FAM6_HASWELL_GT3E: + case INTEL_FAM6_BROADWELL_CORE: + case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: + if (c->x86_cache_bits < 44) + c->x86_cache_bits = 44; + break; + } +} + static void __init l1tf_select_mitigation(void) { u64 half_pa; @@ -641,16 +681,13 @@ static void __init l1tf_select_mitigation(void) if (!boot_cpu_has_bug(X86_BUG_L1TF)) return; + override_cache_bits(&boot_cpu_data); + #if CONFIG_PGTABLE_LEVELS == 2 pr_warn("Kernel not compiled for PAE. No mitigation for L1TF\n"); return; #endif - /* - * This is extremely unlikely to happen because almost all - * systems have far more MAX_PA/2 than RAM can be fit into - * DIMM slots. - */ half_pa = (u64)l1tf_pfn_limit() << PAGE_SHIFT; if (e820_any_mapped(half_pa, ULLONG_MAX - half_pa, E820_RAM)) { pr_warn("System has more than MAX_PA/2 memory. L1TF mitigation not effective.\n"); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 4d3fa79c0f09..b12c0287d6cf 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -798,6 +798,8 @@ void get_cpu_cap(struct cpuinfo_x86 *c) c->x86_phys_bits = 36; #endif + c->x86_cache_bits = c->x86_phys_bits; + if (c->extended_cpuid_level >= 0x8000000a) c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a); diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index e0a34b0d381e..c4dffae5d939 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -273,8 +273,6 @@ static noinline int vmalloc_fault(unsigned long address) if (!(address >= VMALLOC_START && address < VMALLOC_END)) return -1; - WARN_ON_ONCE(in_nmi()); - /* * Synchronize this task's top level page-table * with the 'reference' page table. diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 9075f08b392a..aa84a3c1d418 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -185,7 +185,8 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, } wb_congested = wb_congested_get_create(q->backing_dev_info, - blkcg->css.id, GFP_NOWAIT); + blkcg->css.id, + GFP_NOWAIT | __GFP_NOWARN); if (!wb_congested) { ret = -ENOMEM; goto err_put_css; @@ -193,7 +194,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, /* allocate */ if (!new_blkg) { - new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT); + new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT | __GFP_NOWARN); if (unlikely(!new_blkg)) { ret = -ENOMEM; goto err_put_congested; @@ -1022,7 +1023,7 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css) } spin_lock_init(&blkcg->lock); - INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT); + INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN); INIT_HLIST_HEAD(&blkcg->blkg_list); #ifdef CONFIG_CGROUP_WRITEBACK INIT_LIST_HEAD(&blkcg->cgwb_list); @@ -1238,7 +1239,7 @@ pd_prealloc: if (blkg->pd[pol->plid]) continue; - pd = pol->pd_alloc_fn(GFP_NOWAIT, q->node); + pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q->node); if (!pd) swap(pd, pd_prealloc); if (!pd) { diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index e04a7b8492cf..4e1f49434bbe 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2905,7 +2905,8 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) * for devices that support queuing, otherwise we still have a problem * with sync vs async workloads. */ - if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag) + if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag && + !cfqd->cfq_group_idle) return; WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list)); @@ -3810,7 +3811,8 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, goto out; } - cfqq = kmem_cache_alloc_node(cfq_pool, GFP_NOWAIT | __GFP_ZERO, + cfqq = kmem_cache_alloc_node(cfq_pool, + GFP_NOWAIT | __GFP_ZERO | __GFP_NOWARN, cfqd->queue->node); if (!cfqq) { cfqq = &cfqd->oom_cfqq; diff --git a/block/partitions/aix.c b/block/partitions/aix.c index f3ed7b2d89bf..8e7d358e0226 100644 --- a/block/partitions/aix.c +++ b/block/partitions/aix.c @@ -177,7 +177,7 @@ int aix_partition(struct parsed_partitions *state) u32 vgda_sector = 0; u32 vgda_len = 0; int numlvs = 0; - struct pvd *pvd; + struct pvd *pvd = NULL; struct lv_info { unsigned short pps_per_lv; unsigned short pps_found; @@ -231,10 +231,11 @@ int aix_partition(struct parsed_partitions *state) if (lvip[i].pps_per_lv) foundlvs += 1; } + /* pvd loops depend on n[].name and lvip[].pps_per_lv */ + pvd = alloc_pvd(state, vgda_sector + 17); } put_dev_sector(sect); } - pvd = alloc_pvd(state, vgda_sector + 17); if (pvd) { int numpps = be16_to_cpu(pvd->pp_count); int psn_part1 = be32_to_cpu(pvd->psn_part1); @@ -281,10 +282,14 @@ int aix_partition(struct parsed_partitions *state) next_lp_ix += 1; } for (i = 0; i < state->limit; i += 1) - if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) + if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) { + char tmp[sizeof(n[i].name) + 1]; // null char + + snprintf(tmp, sizeof(tmp), "%s", n[i].name); pr_warn("partition %s (%u pp's found) is " "not contiguous\n", - n[i].name, lvip[i].pps_found); + tmp, lvip[i].pps_found); + } kfree(pvd); } kfree(n); diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 623094457788..644b9abcc67f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4714,6 +4714,42 @@ out: return ret; } +static int binder_ioctl_get_node_info_for_ref(struct binder_proc *proc, + struct binder_node_info_for_ref *info) +{ + struct binder_node *node; + struct binder_context *context = proc->context; + __u32 handle = info->handle; + + if (info->strong_count || info->weak_count || info->reserved1 || + info->reserved2 || info->reserved3) { + binder_user_error("%d BINDER_GET_NODE_INFO_FOR_REF: only handle may be non-zero.", + proc->pid); + return -EINVAL; + } + + /* This ioctl may only be used by the context manager */ + mutex_lock(&context->context_mgr_node_lock); + if (!context->binder_context_mgr_node || + context->binder_context_mgr_node->proc != proc) { + mutex_unlock(&context->context_mgr_node_lock); + return -EPERM; + } + mutex_unlock(&context->context_mgr_node_lock); + + node = binder_get_node_from_ref(proc, handle, true, NULL); + if (!node) + return -EINVAL; + + info->strong_count = node->local_strong_refs + + node->internal_strong_refs; + info->weak_count = node->local_weak_refs; + + binder_put_node(node); + + return 0; +} + static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, struct binder_node_debug_info *info) { struct rb_node *n; @@ -4807,6 +4843,25 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_GET_NODE_INFO_FOR_REF: { + struct binder_node_info_for_ref info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_info_for_ref(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + break; + } case BINDER_GET_NODE_DEBUG_INFO: { struct binder_node_debug_info info; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 9628fa131757..8116cb2fef2d 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2113,6 +2113,8 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) deto = 20; } + /* Make dito, mdat, deto bits to 0s */ + devslp &= ~GENMASK_ULL(24, 2); devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | (mdat << PORT_DEVSLP_MDAT_OFFSET) | (deto << PORT_DEVSLP_DETO_OFFSET) | diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 57b60eeb11c6..b6281e523bf3 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -125,6 +125,7 @@ config BT_HCIUART_LL config BT_HCIUART_3WIRE bool "Three-wire UART (H5) protocol support" depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help The HCI Three-wire UART Transport Layer makes it possible to user the Bluetooth HCI over a serial port interface. The HCI diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 01718d05e952..9e8f0e255de2 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -120,6 +120,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop"); base = of_iomap(np, 0); + of_node_put(np); WARN_ON(!base); clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); diff --git a/drivers/clk/qcom/mdss/mdss-pll-util.c b/drivers/clk/qcom/mdss/mdss-pll-util.c index 881c973ec1b6..d6a148eee68c 100644 --- a/drivers/clk/qcom/mdss/mdss-pll-util.c +++ b/drivers/clk/qcom/mdss/mdss-pll-util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -327,16 +327,6 @@ clk_err: return rc; } -static void mdss_pll_free_bootmem(u32 mem_addr, u32 size) -{ - unsigned long pfn_start, pfn_end, pfn_idx; - - pfn_start = mem_addr >> PAGE_SHIFT; - pfn_end = (mem_addr + size) >> PAGE_SHIFT; - for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++) - free_reserved_page(pfn_to_page(pfn_idx)); -} - static int mdss_pll_util_parse_dt_dfps(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { @@ -367,7 +357,7 @@ static int mdss_pll_util_parse_dt_dfps(struct platform_device *pdev, area = get_vm_area(offsets[1], VM_IOREMAP); if (!area) { rc = -ENOMEM; - goto dfps_mem_err; + goto pnode_err; } virt_add = (unsigned long)area->addr; @@ -394,10 +384,6 @@ addr_err: ioremap_err: if (area) vfree(area->addr); -dfps_mem_err: - /* free the dfps memory here */ - memblock_free(offsets[0], offsets[1]); - mdss_pll_free_bootmem(offsets[0], offsets[1]); pnode_err: if (pnode) of_node_put(pnode); diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index b44f926a6ba0..598b1aa0f4d7 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -1,6 +1,6 @@ /* Qualcomm Crypto Engine driver. * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2440,6 +2440,9 @@ static int _qce_sps_add_sg_data(struct qce_device *pce_dev, struct sps_iovec *iovec = sps_bam_pipe->iovec + sps_bam_pipe->iovec_count; + if (!sg_src) + return -ENOENT; + while (nbytes > 0) { len = min(nbytes, sg_dma_len(sg_src)); nbytes -= len; diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index f68c24a98277..dedfc96acc66 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1363,7 +1363,7 @@ err_sha_v4_algs: err_sha_v3_algs: for (j = 0; j < k; j++) - crypto_unregister_ahash(&sha_v4_algs[j]); + crypto_unregister_ahash(&sha_v3_algs[j]); err_aes_algs: for (j = 0; j < i; j++) @@ -1379,7 +1379,7 @@ static void sahara_unregister_algs(struct sahara_dev *dev) for (i = 0; i < ARRAY_SIZE(aes_algs); i++) crypto_unregister_alg(&aes_algs[i]); - for (i = 0; i < ARRAY_SIZE(sha_v4_algs); i++) + for (i = 0; i < ARRAY_SIZE(sha_v3_algs); i++) crypto_unregister_ahash(&sha_v3_algs[i]); if (dev->version > SAHARA_VERSION_3) diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 9506e8693c81..d8ef1147b344 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -111,24 +111,23 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes); } else { - preempt_disable(); - pagefault_disable(); - enable_kernel_altivec(); - enable_kernel_vsx(); - blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt(desc, &walk); while ((nbytes = walk.nbytes)) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); + enable_kernel_altivec(); aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr, nbytes & AES_BLOCK_MASK, &ctx->enc_key, walk.iv, 1); + pagefault_enable(); + preempt_enable(); + nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, &walk, nbytes); } - - pagefault_enable(); - preempt_enable(); } return ret; @@ -152,24 +151,23 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, ret = crypto_blkcipher_decrypt(&fallback_desc, dst, src, nbytes); } else { - preempt_disable(); - pagefault_disable(); - enable_kernel_altivec(); - enable_kernel_vsx(); - blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt(desc, &walk); while ((nbytes = walk.nbytes)) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); + enable_kernel_altivec(); aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr, nbytes & AES_BLOCK_MASK, &ctx->dec_key, walk.iv, 0); + pagefault_enable(); + preempt_enable(); + nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, &walk, nbytes); } - - pagefault_enable(); - preempt_enable(); } return ret; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 8db791ef2027..95619ee33112 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2132,13 +2132,14 @@ static int pl330_terminate_all(struct dma_chan *chan) pm_runtime_get_sync(pl330->ddma.dev); spin_lock_irqsave(&pch->lock, flags); + spin_lock(&pl330->lock); _stop(pch->thread); - spin_unlock(&pl330->lock); - pch->thread->req[0].desc = NULL; pch->thread->req[1].desc = NULL; pch->thread->req_running = -1; + spin_unlock(&pl330->lock); + power_down = pch->active; pch->active = false; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 5536108aa9db..fe21734bbe5c 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -495,9 +495,10 @@ err_irq_alloc_descs: chip = chip_save; err_gpiochip_add: + chip = chip_save; while (--i >= 0) { - chip--; gpiochip_remove(&chip->gpio); + chip++; } kfree(chip_save); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 896bf29776b0..fb2c1df4f588 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -591,4 +591,4 @@ static int __init tegra_gpio_init(void) { return platform_driver_register(&tegra_gpio_driver); } -postcore_initcall(tegra_gpio_init); +subsys_initcall(tegra_gpio_init); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 98ab08c0aa2d..07541c5670e6 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -30,7 +30,7 @@ struct acpi_gpio_info { }; /* gpio suffixes used for ACPI and device tree lookup */ -static const char * const gpio_suffixes[] = { "gpios", "gpio" }; +static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; #ifdef CONFIG_ACPI void acpi_gpiochip_add(struct gpio_chip *chip); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index eb1da83c9902..8cdd505784ed 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -125,6 +125,8 @@ struct kfd_process *kfd_get_process(const struct task_struct *thread) return ERR_PTR(-EINVAL); process = find_process(thread); + if (!process) + return ERR_PTR(-EINVAL); return process; } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 83141aaa48d3..48bddbf0e871 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -2009,6 +2009,7 @@ struct drm_msm_ext_panel_hdr_metadata *hdr_meta) u32 const version = 0x01; u32 const length = 0x1a; u32 const descriptor_id = 0x00; + u8 checksum; struct hdmi *hdmi; struct drm_connector *connector; @@ -2025,11 +2026,33 @@ struct drm_msm_ext_panel_hdr_metadata *hdr_meta) return; } + /* Setup the line number to send the packet on */ + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control |= BIT(16); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); + + /* Setup the packet to be sent every frame */ + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control |= BIT(1); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); + /* Setup Packet header and payload */ packet_header = type_code | (version << 8) | (length << 16); hdmi_write(hdmi, HDMI_GENERIC0_HDR, packet_header); - packet_payload = (hdr_meta->eotf << 8); + /** + * Checksum is not a mandatory field for + * the HDR infoframe as per CEA-861-3 specification. + * However some HDMI sinks still expect a + * valid checksum to be included as part of + * the infoframe. Hence compute and add + * the checksum to improve sink interoperability + * for our HDR solution on HDMI. + */ + checksum = sde_hdmi_hdr_set_chksum(hdr_meta); + + packet_payload = (hdr_meta->eotf << 8) | checksum; + if (connector->hdr_metadata_type_one) { packet_payload |= (descriptor_id << 16) | (HDMI_GET_LSB(hdr_meta->display_primaries_x[0]) @@ -2083,14 +2106,20 @@ struct drm_msm_ext_panel_hdr_metadata *hdr_meta) hdmi_write(hdmi, HDMI_GENERIC0_6, packet_payload); enable_packet_control: - /* - * GENERIC0_LINE | GENERIC0_CONT | GENERIC0_SEND - * Setup HDMI TX generic packet control - * Enable this packet to transmit every frame - * Enable HDMI TX engine to transmit Generic packet 1 - */ + + /* Flush the contents to the register */ + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control |= BIT(2); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); + + /* Clear the flush bit of the register */ + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control &= ~BIT(2); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); + + /* Start sending the packets*/ packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); - packet_control |= BIT(0) | BIT(1) | BIT(2) | BIT(16); + packet_control |= BIT(0); hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 2aa8d9496c5b..9a15f40bb32c 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -224,7 +224,7 @@ enum hdmi_tx_scdc_access_type { #define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 #define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 -#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 +#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x3f0007 /* for AVI program */ #define HDMI_AVI_INFOFRAME_BUFFER_SIZE \ diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index ecf93f2c07ac..4df6c0af1707 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -125,6 +125,15 @@ static void sde_hdmi_clear_hdr_info(struct drm_bridge *bridge) connector->hdr_supported = false; } +static void sde_hdmi_clear_colorimetry(struct drm_bridge *bridge) +{ + struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct drm_connector *connector = hdmi->connector; + + connector->color_enc_fmt = 0; +} + static void sde_hdmi_clear_vsdb_info(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); @@ -676,6 +685,8 @@ static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) sde_hdmi_clear_vsdbs(bridge); /* Clear HDMI VCDB block info */ sde_hdmi_clear_vcdb_info(bridge); + /* Clear HDMI colorimetry data block info */ + sde_hdmi_clear_colorimetry(bridge); mutex_unlock(&display->display_lock); } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c index 8ce90b9bc162..5600f24bd438 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -73,10 +73,101 @@ static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state) switch (hdr_state) { case HDR_DISABLE: return "HDR_DISABLE"; case HDR_ENABLE: return "HDR_ENABLE"; + case HDR_RESET: return "HDR_RESET"; default: return "HDR_INVALID_STATE"; } } +static u8 sde_hdmi_infoframe_checksum(u8 *ptr, size_t size) +{ + u8 csum = 0; + size_t i; + + /* compute checksum */ + for (i = 0; i < size; i++) + csum += ptr[i]; + + return 256 - csum; +} + +u8 sde_hdmi_hdr_set_chksum(struct drm_msm_ext_panel_hdr_metadata *hdr_meta) +{ + u8 *buff; + u8 *ptr; + u32 length; + u32 size; + u32 chksum = 0; + u32 const type_code = 0x87; + u32 const version = 0x01; + u32 const descriptor_id = 0x00; + + /* length of metadata is 26 bytes */ + length = 0x1a; + /* add 4 bytes for the header */ + size = length + HDMI_INFOFRAME_HEADER_SIZE; + + buff = kzalloc(size, GFP_KERNEL); + + if (!buff) { + SDE_ERROR("invalid buff\n"); + goto err_alloc; + } + + ptr = buff; + + buff[0] = type_code; + buff[1] = version; + buff[2] = length; + buff[3] = 0; + /* start infoframe payload */ + buff += HDMI_INFOFRAME_HEADER_SIZE; + + buff[0] = hdr_meta->eotf; + buff[1] = descriptor_id; + + buff[2] = hdr_meta->display_primaries_x[0] & 0xff; + buff[3] = hdr_meta->display_primaries_x[0] >> 8; + + buff[4] = hdr_meta->display_primaries_x[1] & 0xff; + buff[5] = hdr_meta->display_primaries_x[1] >> 8; + + buff[6] = hdr_meta->display_primaries_x[2] & 0xff; + buff[7] = hdr_meta->display_primaries_x[2] >> 8; + + buff[8] = hdr_meta->display_primaries_y[0] & 0xff; + buff[9] = hdr_meta->display_primaries_y[0] >> 8; + + buff[10] = hdr_meta->display_primaries_y[1] & 0xff; + buff[11] = hdr_meta->display_primaries_y[1] >> 8; + + buff[12] = hdr_meta->display_primaries_y[2] & 0xff; + buff[13] = hdr_meta->display_primaries_y[2] >> 8; + + buff[14] = hdr_meta->white_point_x & 0xff; + buff[15] = hdr_meta->white_point_x >> 8; + buff[16] = hdr_meta->white_point_y & 0xff; + buff[17] = hdr_meta->white_point_y >> 8; + + buff[18] = hdr_meta->max_luminance & 0xff; + buff[19] = hdr_meta->max_luminance >> 8; + + buff[20] = hdr_meta->min_luminance & 0xff; + buff[21] = hdr_meta->min_luminance >> 8; + + buff[22] = hdr_meta->max_content_light_level & 0xff; + buff[23] = hdr_meta->max_content_light_level >> 8; + + buff[24] = hdr_meta->max_average_light_level & 0xff; + buff[25] = hdr_meta->max_average_light_level >> 8; + + chksum = sde_hdmi_infoframe_checksum(ptr, size); + + kfree(ptr); + +err_alloc: + return chksum; +} + /** * sde_hdmi_dump_regs - utility to dump HDMI regs * @hdmi_display: Pointer to private display handle @@ -984,18 +1075,23 @@ u8 sde_hdmi_hdr_get_ops(u8 curr_state, u8 new_state) { - /** There could be 3 valid state transitions: + /** There could be 4 valid state transitions: * 1. HDR_DISABLE -> HDR_ENABLE * * In this transition, we shall start sending * HDR metadata with metadata from the HDR clip * - * 2. HDR_ENABLE -> HDR_ENABLE + * 2. HDR_ENABLE -> HDR_RESET * * In this transition, we will keep sending * HDR metadata but with EOTF and metadata as 0 * - * 3. HDR_ENABLE -> HDR_DISABLE + * 3. HDR_RESET -> HDR_ENABLE + * + * In this transition, we will start sending + * HDR metadata with metadata from the HDR clip + * + * 4. HDR_RESET -> HDR_DISABLE * * In this transition, we will stop sending * metadata to the sink and clear PKT_CTRL register @@ -1009,12 +1105,18 @@ u8 sde_hdmi_hdr_get_ops(u8 curr_state, sde_hdmi_hdr_sname(new_state)); return HDR_SEND_INFO; } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_RESET)) { + HDMI_UTIL_DEBUG("State changed %s ---> %s\n", + sde_hdmi_hdr_sname(curr_state), + sde_hdmi_hdr_sname(new_state)); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_RESET) && (new_state == HDR_ENABLE)) { HDMI_UTIL_DEBUG("State changed %s ---> %s\n", sde_hdmi_hdr_sname(curr_state), sde_hdmi_hdr_sname(new_state)); return HDR_SEND_INFO; - } else if ((curr_state == HDR_ENABLE) + } else if ((curr_state == HDR_RESET) && (new_state == HDR_DISABLE)) { HDMI_UTIL_DEBUG("State changed %s ---> %s\n", sde_hdmi_hdr_sname(curr_state), diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 340e665f2c28..985d8c3e605c 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -141,8 +141,9 @@ enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask { }; enum sde_hdmi_hdr_state { - HDR_DISABLE, - HDR_ENABLE + HDR_DISABLE = DRM_MSM_HDR_DISABLE, + HDR_ENABLE = DRM_MSM_HDR_ENABLE, + HDR_RESET = DRM_MSM_HDR_RESET }; enum sde_hdmi_hdr_op { @@ -200,5 +201,6 @@ u8 sde_hdmi_hdr_get_ops(u8 curr_state, u8 new_state); void sde_hdmi_ctrl_reset(struct hdmi *hdmi); void sde_hdmi_ctrl_cfg(struct hdmi *hdmi, bool power_on); +u8 sde_hdmi_hdr_set_chksum(struct drm_msm_ext_panel_hdr_metadata *hdr_meta); #endif /* _SDE_HDMI_UTIL_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index a986f5db2c41..5f6b93931c35 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -19,6 +19,8 @@ #include "sde_splash.h" #include <linux/workqueue.h> #include <linux/atomic.h> +#include <linux/cpu.h> +#include <linux/device.h> #define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\ (c) ? (c)->base.base.id : -1, ##__VA_ARGS__) @@ -574,7 +576,14 @@ void sde_connector_prepare_fence(struct drm_connector *connector) static void wake_up_cpu(struct work_struct *work) { - if (!cpu_up(1)) + struct device *cpu_dev = NULL; + + cpu_dev = get_cpu_device(1); + if (!cpu_dev) { + pr_err("Could not get cpu1 device\n"); + return; + } + if (!device_online(cpu_dev)) pr_info("cpu1 is online\n"); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index e7e581d6a8ff..1bfc4807ce5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -23,6 +23,10 @@ #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER #include "priv.h" +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) +#include <asm/dma-iommu.h> +#endif + static int nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) { @@ -85,6 +89,15 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) unsigned long pgsize_bitmap; int ret; +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) + if (dev->archdata.mapping) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +#endif + if (!tdev->func->iommu_bit) return; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index a188a3959f1a..6ad827b93ae1 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -823,7 +823,7 @@ static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx) int ret, i; ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id)); - if (ret < ARRAY_SIZE(id) || id[0] == 0x00) { + if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) { dev_err(ctx->dev, "read id failed\n"); ctx->error = -EIO; return; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 02f0cb7eb16c..55ebc0a8e26c 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1403,6 +1403,45 @@ long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, kgsl_context_put(context); break; } + case KGSL_PROP_SECURE_BUFFER_ALIGNMENT: + { + unsigned int align; + + if (param->sizebytes != sizeof(unsigned int)) { + result = -EINVAL; + break; + } + /* + * XPUv2 impose the constraint of 1MB memory alignment, + * on the other hand Hypervisor does not have such + * constraints. So driver should fulfill such + * requirements when allocating secure memory. + */ + align = MMU_FEATURE(&dev_priv->device->mmu, + KGSL_MMU_HYP_SECURE_ALLOC) ? PAGE_SIZE : SZ_1M; + + if (copy_to_user(param->value, &align, sizeof(align))) + result = -EFAULT; + + break; + } + case KGSL_PROP_SECURE_CTXT_SUPPORT: + { + unsigned int secure_ctxt; + + if (param->sizebytes != sizeof(unsigned int)) { + result = -EINVAL; + break; + } + + secure_ctxt = dev_priv->device->mmu.secured ? 1 : 0; + + if (copy_to_user(param->value, &secure_ctxt, + sizeof(secure_ctxt))) + result = -EFAULT; + + break; + } default: if (is_compat_task()) result = dev_priv->device->ftbl->getproperty_compat( diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 0da9adc49574..6ddda6232203 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -46,8 +46,9 @@ /** register definition **/ /* FFSR - 0x300 */ -#define FFSR_FT_STOPPED BIT(1) +#define FFSR_FT_STOPPED_BIT 1 /* FFCR - 0x304 */ +#define FFCR_FON_MAN_BIT 6 #define FFCR_FON_MAN BIT(6) #define FFCR_STOP_FI BIT(12) @@ -93,9 +94,9 @@ static void tpiu_disable_hw(struct tpiu_drvdata *drvdata) /* Generate manual flush */ writel_relaxed(FFCR_STOP_FI | FFCR_FON_MAN, drvdata->base + TPIU_FFCR); /* Wait for flush to complete */ - coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN, 0); + coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN_BIT, 0); /* Wait for formatter to stop */ - coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED, 1); + coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED_BIT, 1); CS_LOCK(drvdata->base); } diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 9b0cc7baca73..24677cdb1bf5 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -87,7 +87,7 @@ static int coresight_find_link_inport(struct coresight_device *csdev) dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n", dev_name(&parent->dev), dev_name(&csdev->dev)); - return 0; + return -ENODEV; } static int coresight_find_link_outport(struct coresight_device *csdev) @@ -108,7 +108,7 @@ static int coresight_find_link_outport(struct coresight_device *csdev) dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n", dev_name(&csdev->dev), dev_name(&child->dev)); - return 0; + return -ENODEV; } static int coresight_enable_sink(struct coresight_device *csdev) @@ -156,6 +156,9 @@ static int coresight_enable_link(struct coresight_device *csdev) else refport = 0; + if (refport < 0) + return refport; + if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { ret = link_ops(csdev)->enable(csdev, inport, outport); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 85f39cc3e276..47581c32b1e1 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -128,6 +128,7 @@ #define SBREG_BAR 0x10 #define SBREG_SMBCTRL 0xc6000c +#define SBREG_SMBCTRL_DNV 0xcf000c /* Host status bits for SMBPCISTS */ #define SMBPCISTS_INTS 0x08 @@ -1251,7 +1252,11 @@ static void i801_add_tco(struct i801_priv *priv) spin_unlock(&p2sb_spinlock); res = &tco_res[ICH_RES_MEM_OFF]; - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; + else + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + res->end = res->start + 3; res->flags = IORESOURCE_MEM; diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index d72953f2df23..198e55829226 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -2330,6 +2330,12 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct i2c_msm_ctrl *ctrl = i2c_get_adapdata(adap); struct i2c_msm_xfer *xfer = &ctrl->xfer; + if (num < 1) { + dev_err(ctrl->dev, + "error on number of msgs(%d) received\n", num); + return -EINVAL; + } + if (IS_ERR_OR_NULL(msgs)) { dev_err(ctrl->dev, " error on msgs Accessing invalid pointer location\n"); return PTR_ERR(msgs); diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 0b20449e48cf..da9acec1a029 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -533,6 +533,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) { u8 rx_watermark; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; + unsigned long flags; /* Clear and enable Rx full interrupt. */ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK); @@ -548,6 +549,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) rx_watermark = IIC_RX_FIFO_DEPTH; xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1); + local_irq_save(flags); if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, @@ -558,6 +560,8 @@ static void xiic_start_recv(struct xiic_i2c *i2c) xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0)); + local_irq_restore(flags); + if (i2c->nmsgs == 1) /* very last, enable bus not busy as well */ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index d57a78ec7425..1454290078de 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -544,6 +544,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) dgid = (union ib_gid *) &addr->sib_addr; pkey = ntohs(addr->sib_pkey); + mutex_lock(&lock); list_for_each_entry(cur_dev, &dev_list, list) { for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { if (!rdma_cap_af_ib(cur_dev->device, p)) @@ -567,18 +568,19 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) cma_dev = cur_dev; sgid = gid; id_priv->id.port_num = p; + goto found; } } } } - - if (!cma_dev) - return -ENODEV; + mutex_unlock(&lock); + return -ENODEV; found: cma_attach_to_dev(id_priv, cma_dev); - addr = (struct sockaddr_ib *) cma_src_addr(id_priv); - memcpy(&addr->sib_addr, &sgid, sizeof sgid); + mutex_unlock(&lock); + addr = (struct sockaddr_ib *)cma_src_addr(id_priv); + memcpy(&addr->sib_addr, &sgid, sizeof(sgid)); cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); return 0; } @@ -1280,9 +1282,16 @@ static bool cma_match_net_dev(const struct rdma_cm_id *id, (addr->src_addr.ss_family == AF_IB || cma_protocol_roce_dev_port(id->device, port_num)); - return !addr->dev_addr.bound_dev_if || - (net_eq(dev_net(net_dev), addr->dev_addr.net) && - addr->dev_addr.bound_dev_if == net_dev->ifindex); + /* + * Net namespaces must match, and if the listner is listening + * on a specific netdevice than netdevice must match as well. + */ + if (net_eq(dev_net(net_dev), addr->dev_addr.net) && + (!!addr->dev_addr.bound_dev_if == + (addr->dev_addr.bound_dev_if == net_dev->ifindex))) + return true; + else + return false; } static struct rdma_id_private *cma_find_listener( diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index f74b11542603..a338e60836ee 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -992,12 +992,14 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even skb_queue_head_init(&skqueue); + netif_tx_lock_bh(p->dev); spin_lock_irq(&priv->lock); set_bit(IPOIB_FLAG_OPER_UP, &p->flags); if (p->neigh) while ((skb = __skb_dequeue(&p->neigh->queue))) __skb_queue_tail(&skqueue, skb); spin_unlock_irq(&priv->lock); + netif_tx_unlock_bh(p->dev); while ((skb = __skb_dequeue(&skqueue))) { skb->dev = p->dev; diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 88dfe3008cf4..be2f2521c1c5 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1593,10 +1593,11 @@ static int mxt_get_object_table(struct mxt_data *data) break; case MXT_TOUCH_MULTI_T9: data->multitouch = MXT_TOUCH_MULTI_T9; + /* Only handle messages from first T9 instance */ data->T9_reportid_min = min_id; - data->T9_reportid_max = max_id; - data->num_touchids = object->num_report_ids - * mxt_obj_instances(object); + data->T9_reportid_max = min_id + + object->num_report_ids - 1; + data->num_touchids = object->num_report_ids; break; case MXT_SPT_MESSAGECOUNT_T44: data->T44_address = object->start_address; diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 347aaaa5a7ea..fc6eb752ab35 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1219,6 +1219,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev) /* Sync our overflow flag, as we believe we're up to speed */ q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons); + writel(q->cons, q->cons_reg); return IRQ_HANDLED; } diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 566572ae051e..e44253426b28 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -30,7 +30,7 @@ #include <asm/dma-iommu.h> #include "iommu-debug.h" -#if defined(CONFIG_IOMMU_DEBUG_TRACKING) || defined(CONFIG_IOMMU_TESTS) +#if defined(CONFIG_IOMMU_TESTS) static const char *iommu_debug_attr_to_string(enum iommu_attr attr) { diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index dfb868e2d129..624e7ff76166 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -44,7 +44,7 @@ struct ipmmu_vmsa_domain { struct io_pgtable_ops *iop; unsigned int context_id; - spinlock_t lock; /* Protects mappings */ + struct mutex mutex; /* Protects mappings */ }; struct ipmmu_vmsa_archdata { @@ -464,7 +464,7 @@ static struct iommu_domain *ipmmu_domain_alloc(unsigned type) if (!domain) return NULL; - spin_lock_init(&domain->lock); + mutex_init(&domain->mutex); return &domain->io_domain; } @@ -488,7 +488,6 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; struct ipmmu_vmsa_device *mmu = archdata->mmu; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); - unsigned long flags; unsigned int i; int ret = 0; @@ -497,7 +496,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, return -ENXIO; } - spin_lock_irqsave(&domain->lock, flags); + mutex_lock(&domain->mutex); if (!domain->mmu) { /* The domain hasn't been used yet, initialize it. */ @@ -513,7 +512,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, ret = -EINVAL; } - spin_unlock_irqrestore(&domain->lock, flags); + mutex_unlock(&domain->mutex); if (ret < 0) return ret; diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index d7af88534971..6fb34bf0f352 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -216,6 +216,7 @@ static int bcm7038_l1_set_affinity(struct irq_data *d, return 0; } +#ifdef CONFIG_SMP static void bcm7038_l1_cpu_offline(struct irq_data *d) { struct cpumask *mask = irq_data_get_affinity_mask(d); @@ -240,6 +241,7 @@ static void bcm7038_l1_cpu_offline(struct irq_data *d) } irq_set_affinity_locked(d, &new_affinity, false); } +#endif static int __init bcm7038_l1_init_one(struct device_node *dn, unsigned int idx, @@ -292,7 +294,9 @@ static struct irq_chip bcm7038_l1_irq_chip = { .irq_mask = bcm7038_l1_mask, .irq_unmask = bcm7038_l1_unmask, .irq_set_affinity = bcm7038_l1_set_affinity, +#ifdef CONFIG_SMP .irq_cpu_offline = bcm7038_l1_cpu_offline, +#endif }; static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 82e00e3ad0e0..c3d7a1461043 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -67,7 +67,10 @@ struct its_node { unsigned long phys_base; struct its_cmd_block *cmd_base; struct its_cmd_block *cmd_write; - void *tables[GITS_BASER_NR_REGS]; + struct { + void *base; + u32 order; + } tables[GITS_BASER_NR_REGS]; struct its_collection *collections; struct list_head its_device_list; u64 flags; @@ -77,6 +80,9 @@ struct its_node { #define ITS_ITT_ALIGN SZ_256 +/* Convert page order to size in bytes */ +#define PAGE_ORDER_TO_SIZE(o) (PAGE_SIZE << (o)) + struct event_lpi_map { unsigned long *lpi_map; u16 *col_map; @@ -816,9 +822,10 @@ static void its_free_tables(struct its_node *its) int i; for (i = 0; i < GITS_BASER_NR_REGS; i++) { - if (its->tables[i]) { - free_page((unsigned long)its->tables[i]); - its->tables[i] = NULL; + if (its->tables[i].base) { + free_pages((unsigned long)its->tables[i].base, + its->tables[i].order); + its->tables[i].base = NULL; } } } @@ -851,7 +858,6 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) u64 type = GITS_BASER_TYPE(val); u64 entry_size = GITS_BASER_ENTRY_SIZE(val); int order = get_order(psz); - int alloc_size; int alloc_pages; u64 tmp; void *base; @@ -883,8 +889,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) } } - alloc_size = (1 << order) * PAGE_SIZE; - alloc_pages = (alloc_size / psz); +retry_alloc_baser: + alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); if (alloc_pages > GITS_BASER_PAGES_MAX) { alloc_pages = GITS_BASER_PAGES_MAX; order = get_order(GITS_BASER_PAGES_MAX * psz); @@ -898,7 +904,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) goto out_free; } - its->tables[i] = base; + its->tables[i].base = base; + its->tables[i].order = order; retry_baser: val = (virt_to_phys(base) | @@ -936,7 +943,7 @@ retry_baser: shr = tmp & GITS_BASER_SHAREABILITY_MASK; if (!shr) { cache = GITS_BASER_nC; - __flush_dcache_area(base, alloc_size); + __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); } goto retry_baser; } @@ -947,13 +954,16 @@ retry_baser: * size and retry. If we reach 4K, then * something is horribly wrong... */ + free_pages((unsigned long)base, order); + its->tables[i].base = NULL; + switch (psz) { case SZ_16K: psz = SZ_4K; - goto retry_baser; + goto retry_alloc_baser; case SZ_64K: psz = SZ_16K; - goto retry_baser; + goto retry_alloc_baser; } } @@ -966,7 +976,7 @@ retry_baser: } pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n", - (int)(alloc_size / entry_size), + (int)(PAGE_ORDER_TO_SIZE(order) / entry_size), its_base_type_string[type], (unsigned long)virt_to_phys(base), psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index b0b534622734..25b5a2427705 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -517,7 +517,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); irqnr = irqstat & GICC_IAR_INT_ID_MASK; - if (likely(irqnr > 15 && irqnr < 1021)) { + if (likely(irqnr > 15 && irqnr < 1020)) { if (static_key_true(&supports_deactivate)) writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); handle_domain_irq(gic->domain, irqnr, regs); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index f9512bfa6c3c..0a41132ffba7 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -530,8 +530,9 @@ init_pmu(void) int timeout; struct adb_request req; - out_8(&via[B], via[B] | TREQ); /* negate TREQ */ - out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ + /* Negate TREQ. Set TACK to input and TREQ to output. */ + out_8(&via[B], in_8(&via[B]) | TREQ); + out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; @@ -1453,8 +1454,8 @@ pmu_sr_intr(void) struct adb_request *req; int bite = 0; - if (via[B] & TREQ) { - printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); + if (in_8(&via[B]) & TREQ) { + printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B])); out_8(&via[IFR], SR_INT); return NULL; } diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 1452ed9aacb4..54c308e6704f 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -454,6 +454,8 @@ static int run_complete_job(struct kcopyd_job *job) if (atomic_dec_and_test(&kc->nr_jobs)) wake_up(&kc->destroyq); + cond_resched(); + return 0; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index bb77d20f2ef2..dfe19d74c119 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4190,6 +4190,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) s->failed++; if (rdev && !test_bit(Faulty, &rdev->flags)) do_recovery = 1; + else if (!rdev) { + rdev = rcu_dereference( + conf->disks[i].replacement); + if (rdev && !test_bit(Faulty, &rdev->flags)) + do_recovery = 1; + } } } if (test_bit(STRIPE_SYNCING, &sh->state)) { diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c index 58bfdb77a492..bf5296e6d071 100644 --- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c @@ -570,15 +570,13 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, k_ioctl = *ptr; switch (k_ioctl.id) { case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { + struct msm_buf_mngr_info buf_info, *tmp = NULL; if (k_ioctl.size != sizeof(struct msm_buf_mngr_info)) return -EINVAL; if (!k_ioctl.ioctl_ptr) return -EINVAL; -#ifndef CONFIG_COMPAT - { - struct msm_buf_mngr_info buf_info, *tmp = NULL; - + if (!is_compat_task()) { MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr, sizeof(tmp)); if (copy_from_user(&buf_info, tmp, @@ -587,7 +585,7 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, } k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; } -#endif + argp = &k_ioctl; rc = msm_cam_buf_mgr_ops(cmd, argp); } diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index c288568edfbd..81ce5813cec4 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1091,6 +1091,15 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) b->m.planes[i].m.userptr = buffer_info->uvaddr[i]; b->m.planes[i].reserved[0] = buffer_info->fd[i]; b->m.planes[i].reserved[1] = buffer_info->buff_off[i]; + + b->m.planes[i].reserved[2] = buffer_info->crop_data.nLeft; + b->m.planes[i].reserved[3] = buffer_info->crop_data.nTop; + b->m.planes[i].reserved[4] = buffer_info->crop_data.nWidth; + b->m.planes[i].reserved[5] = buffer_info->crop_data.nHeight; + b->m.planes[i].reserved[6] = + buffer_info->crop_data.width_height[0]; + b->m.planes[i].reserved[7] = + buffer_info->crop_data.width_height[1]; if (!(inst->flags & VIDC_SECURE) && !b->m.planes[i].m.userptr) { dprintk(VIDC_ERR, "%s: Failed to find user virtual address, %#lx, %d, %d\n", diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index ee3cfb88855c..610ed9c6fed9 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2061,6 +2061,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data) int extra_idx = 0; int64_t time_usec = 0; struct vb2_v4l2_buffer *vbuf = NULL; + struct buffer_info *buffer_info = NULL; if (!response) { dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); @@ -2102,6 +2103,26 @@ static void handle_fbd(enum hal_command_response cmd, void *data) "fbd:Overflow bytesused = %d; length = %d\n", vb->planes[0].bytesused, vb->planes[0].length); + + buffer_info = device_to_uvaddr(&inst->registeredbufs, + fill_buf_done->packet_buffer1); + + if (!buffer_info) { + dprintk(VIDC_ERR, + "%s buffer not found in registered list\n", + __func__); + return; + } + + buffer_info->crop_data.nLeft = fill_buf_done->start_x_coord; + buffer_info->crop_data.nTop = fill_buf_done->start_y_coord; + buffer_info->crop_data.nWidth = fill_buf_done->frame_width; + buffer_info->crop_data.nHeight = fill_buf_done->frame_height; + buffer_info->crop_data.width_height[0] = + inst->prop.width[CAPTURE_PORT]; + buffer_info->crop_data.width_height[1] = + inst->prop.height[CAPTURE_PORT]; + if (!(fill_buf_done->flags1 & HAL_BUFFERFLAG_TIMESTAMPINVALID)) { time_usec = fill_buf_done->timestamp_hi; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 2a4033598bd2..08dad912bd57 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -329,6 +329,14 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst); int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst); void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type); +struct crop_info { + u32 nLeft; + u32 nTop; + u32 nWidth; + u32 nHeight; + u32 width_height[MAX_PORT_NUM]; +}; + struct buffer_info { struct list_head list; int type; @@ -348,6 +356,7 @@ struct buffer_info { bool mapped[VIDEO_MAX_PLANES]; int same_fd_ref[VIDEO_MAX_PLANES]; struct timeval timestamp; + struct crop_info crop_data; }; struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list, diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 0c1a42bf27fd..1c37d5a78822 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1366,6 +1366,11 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) struct vb2_buffer *vb; int ret; + if (q->error) { + dprintk(1, "fatal error occurred on queue\n"); + return -EIO; + } + vb = q->bufs[index]; switch (vb->state) { diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index c646784c5a7d..fbec711c4195 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -714,6 +714,7 @@ sm501_create_subdev(struct sm501_devdata *sm, char *name, smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; smdev->pdev.dev.parent = sm->dev; + smdev->pdev.dev.coherent_dma_mask = 0xffffffff; if (res_count) { smdev->pdev.resource = (struct resource *)(smdev+1); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index e4e4b22eebc9..4a0f076c91ba 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -224,14 +224,13 @@ static int ti_tscadc_probe(struct platform_device *pdev) * The TSC_ADC_SS controller design assumes the OCP clock is * at least 6x faster than the ADC clock. */ - clk = clk_get(&pdev->dev, "adc_tsc_fck"); + clk = devm_clk_get(&pdev->dev, "adc_tsc_fck"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get TSC fck\n"); err = PTR_ERR(clk); goto err_disable_clk; } clock_rate = clk_get_rate(clk); - clk_put(clk); tscadc->clk_div = clock_rate / ADC_CLK; /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c index 90520d76633f..9cde4c5bfba4 100644 --- a/drivers/misc/hmc6352.c +++ b/drivers/misc/hmc6352.c @@ -27,6 +27,7 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/sysfs.h> +#include <linux/nospec.h> static DEFINE_MUTEX(compass_mutex); @@ -50,6 +51,7 @@ static int compass_store(struct device *dev, const char *buf, size_t count, return ret; if (val >= strlen(map)) return -EINVAL; + val = array_index_nospec(val, strlen(map)); mutex_lock(&compass_mutex); ret = compass_command(c, map[val]); mutex_unlock(&compass_mutex); diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 2a6eaf1122b4..8e06e1020ad9 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -47,11 +47,18 @@ #include <linux/vmalloc.h> #include <linux/mman.h> #include <asm/cacheflush.h> +#include <linux/list.h> +#include <linux/sched.h> +#include <linux/uaccess.h> #ifdef CONFIG_IDE #include <linux/ide.h> #endif +struct lkdtm_list { + struct list_head node; +}; + /* * Make sure our attempts to over run the kernel stack doesn't trigger * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we @@ -88,6 +95,9 @@ enum ctype { CT_EXCEPTION, CT_LOOP, CT_OVERFLOW, + CT_CORRUPT_LIST_ADD, + CT_CORRUPT_LIST_DEL, + CT_CORRUPT_USER_DS, CT_CORRUPT_STACK, CT_UNALIGNED_LOAD_STORE_WRITE, CT_OVERWRITE_ALLOCATION, @@ -126,6 +136,9 @@ static char* cp_type[] = { "EXCEPTION", "LOOP", "OVERFLOW", + "CORRUPT_LIST_ADD", + "CORRUPT_LIST_DEL", + "CORRUPT_USER_DS", "CORRUPT_STACK", "UNALIGNED_LOAD_STORE_WRITE", "OVERWRITE_ALLOCATION", @@ -548,6 +561,75 @@ static void lkdtm_do_action(enum ctype which) do_overwritten(); break; } + case CT_CORRUPT_LIST_ADD: { + /* + * Initially, an empty list via LIST_HEAD: + * test_head.next = &test_head + * test_head.prev = &test_head + */ + LIST_HEAD(test_head); + struct lkdtm_list good, bad; + void *target[2] = { }; + void *redirection = ⌖ + + pr_info("attempting good list addition\n"); + + /* + * Adding to the list performs these actions: + * test_head.next->prev = &good.node + * good.node.next = test_head.next + * good.node.prev = test_head + * test_head.next = good.node + */ + list_add(&good.node, &test_head); + + pr_info("attempting corrupted list addition\n"); + /* + * In simulating this "write what where" primitive, the "what" is + * the address of &bad.node, and the "where" is the address held + * by "redirection". + */ + test_head.next = redirection; + list_add(&bad.node, &test_head); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_add() corruption not detected!\n"); + break; + } + case CT_CORRUPT_LIST_DEL: { + LIST_HEAD(test_head); + struct lkdtm_list item; + void *target[2] = { }; + void *redirection = ⌖ + + list_add(&item.node, &test_head); + + pr_info("attempting good list removal\n"); + list_del(&item.node); + + pr_info("attempting corrupted list removal\n"); + list_add(&item.node, &test_head); + + /* As with the list_add() test above, this corrupts "next". */ + item.node.next = redirection; + list_del(&item.node); + + if (target[0] == NULL && target[1] == NULL) + pr_err("Overwrite did not happen, but no BUG?!\n"); + else + pr_err("list_del() corruption not detected!\n"); + break; + } + case CT_CORRUPT_USER_DS: { + pr_info("setting bad task size limit\n"); + set_fs(KERNEL_DS); + + /* Make sure we do not keep running with a KERNEL_DS! */ + force_sig(SIGKILL, current); + break; + } case CT_NONE: default: break; diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index bdc7fcd80eca..9dcdc6f41ceb 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -151,7 +151,7 @@ static int mei_nfc_if_version(struct mei_cl *cl, ret = 0; bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); - if (bytes_recv < if_version_length) { + if (bytes_recv < 0 || bytes_recv < if_version_length) { dev_err(bus->dev, "Could not read IF version\n"); ret = -EIO; goto err; diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index adab5bbb642a..d5b84d68f988 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -230,8 +230,11 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!pci_dev_run_wake(pdev)) mei_me_set_pm_domain(dev); - if (mei_pg_is_enabled(dev)) + if (mei_pg_is_enabled(dev)) { pm_runtime_put_noidle(&pdev->dev); + if (hw->d0i3_supported) + pm_runtime_allow(&pdev->dev); + } dev_dbg(&pdev->dev, "initialization successful.\n"); diff --git a/drivers/misc/mic/scif/scif_api.c b/drivers/misc/mic/scif/scif_api.c index ddc9e4b08b5c..56efa9d18a9a 100644 --- a/drivers/misc/mic/scif/scif_api.c +++ b/drivers/misc/mic/scif/scif_api.c @@ -370,11 +370,10 @@ int scif_bind(scif_epd_t epd, u16 pn) goto scif_bind_exit; } } else { - pn = scif_get_new_port(); - if (!pn) { - ret = -ENOSPC; + ret = scif_get_new_port(); + if (ret < 0) goto scif_bind_exit; - } + pn = ret; } ep->state = SCIFEP_BOUND; @@ -648,13 +647,12 @@ int __scif_connect(scif_epd_t epd, struct scif_port_id *dst, bool non_block) err = -EISCONN; break; case SCIFEP_UNBOUND: - ep->port.port = scif_get_new_port(); - if (!ep->port.port) { - err = -ENOSPC; - } else { - ep->port.node = scif_info.nodeid; - ep->conn_async_state = ASYNC_CONN_IDLE; - } + err = scif_get_new_port(); + if (err < 0) + break; + ep->port.port = err; + ep->port.node = scif_info.nodeid; + ep->conn_async_state = ASYNC_CONN_IDLE; /* Fall through */ case SCIFEP_BOUND: /* diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 71b64550b591..a1bca836e506 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -757,14 +757,14 @@ static int kim_probe(struct platform_device *pdev) err = gpio_request(kim_gdata->nshutdown, "kim"); if (unlikely(err)) { pr_err(" gpio %d request failed ", kim_gdata->nshutdown); - return err; + goto err_sysfs_group; } /* Configure nShutdown GPIO as output=0 */ err = gpio_direction_output(kim_gdata->nshutdown, 0); if (unlikely(err)) { pr_err(" unable to configure gpio %d", kim_gdata->nshutdown); - return err; + goto err_sysfs_group; } /* get reference of pdev for request_firmware */ diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 518e2dec2aa2..5e9122cd3898 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -45,6 +45,7 @@ #include <linux/seq_file.h> #include <linux/vmw_vmci_defs.h> #include <linux/vmw_vmci_api.h> +#include <linux/io.h> #include <asm/hypervisor.h> MODULE_AUTHOR("VMware, Inc."); diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index bb580bc16445..c07f21b20463 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -59,9 +59,9 @@ static int __init init_soleng_maps(void) return -ENXIO; } } - printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n", - soleng_flash_map.phys & 0x1fffffff, - soleng_eprom_map.phys & 0x1fffffff); + printk(KERN_NOTICE "Solution Engine: Flash at 0x%pap, EPROM at 0x%pap\n", + &soleng_flash_map.phys, + &soleng_eprom_map.phys); flash_mtd->owner = THIS_MODULE; eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 6d19835b80a9..0d244dac1ccb 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -160,8 +160,12 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count, pr_debug("MTD_read\n"); - if (*ppos + count > mtd->size) - count = mtd->size - *ppos; + if (*ppos + count > mtd->size) { + if (*ppos < mtd->size) + count = mtd->size - *ppos; + else + count = 0; + } if (!count) return 0; @@ -246,7 +250,7 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c pr_debug("MTD_write\n"); - if (*ppos == mtd->size) + if (*ppos >= mtd->size) return -ENOSPC; if (*ppos + count > mtd->size) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index ffcb64bc2bf8..16ca37e18512 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1849,8 +1849,10 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) cond_resched(); e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) + if (!e) { + err = -ENOMEM; goto out_free; + } e->pnum = aeb->pnum; e->ec = aeb->ec; @@ -1871,8 +1873,10 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) cond_resched(); e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) + if (!e) { + err = -ENOMEM; goto out_free; + } e->pnum = aeb->pnum; e->ec = aeb->ec; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index cef53f2d9854..ce20bc939b38 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -185,6 +185,9 @@ struct bcmgenet_mib_counters { #define UMAC_MAC1 0x010 #define UMAC_MAX_FRAME_LEN 0x014 +#define UMAC_MODE 0x44 +#define MODE_LINK_STATUS (1 << 5) + #define UMAC_EEE_CTRL 0x064 #define EN_LPI_RX_PAUSE (1 << 0) #define EN_LPI_TX_PFC (1 << 1) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index e96d1f95bb47..4c73feca4842 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -167,8 +167,14 @@ void bcmgenet_mii_setup(struct net_device *dev) static int bcmgenet_fixed_phy_link_update(struct net_device *dev, struct fixed_phy_status *status) { - if (dev && dev->phydev && status) - status->link = dev->phydev->link; + struct bcmgenet_priv *priv; + u32 reg; + + if (dev && dev->phydev && status) { + priv = netdev_priv(dev); + reg = bcmgenet_umac_readl(priv, UMAC_MODE); + status->link = !!(reg & MODE_LINK_STATUS); + } return 0; } diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index b20bce2c7da1..0433fdebda25 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -2683,7 +2683,6 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ enic->port_mtu = enic->config.mtu; - (void)enic_change_mtu(netdev, enic->port_mtu); err = enic_set_mac_addr(netdev, enic->mac_addr); if (err) { @@ -2732,6 +2731,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features |= NETIF_F_HIGHDMA; netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->mtu = enic->port_mtu; err = register_netdev(netdev); if (err) { diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index ea693bbf56d8..1c300259d70a 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2569,7 +2569,6 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu) } mvneta_start_dev(pp); - mvneta_port_up(pp); netdev_update_features(dev); diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index b28e73ea2c25..f39ad0e66637 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2388,26 +2388,20 @@ static int qlge_update_hw_vlan_features(struct net_device *ndev, return status; } -static netdev_features_t qlge_fix_features(struct net_device *ndev, - netdev_features_t features) -{ - int err; - - /* Update the behavior of vlan accel in the adapter */ - err = qlge_update_hw_vlan_features(ndev, features); - if (err) - return err; - - return features; -} - static int qlge_set_features(struct net_device *ndev, netdev_features_t features) { netdev_features_t changed = ndev->features ^ features; + int err; + + if (changed & NETIF_F_HW_VLAN_CTAG_RX) { + /* Update the behavior of vlan accel in the adapter */ + err = qlge_update_hw_vlan_features(ndev, features); + if (err) + return err; - if (changed & NETIF_F_HW_VLAN_CTAG_RX) qlge_vlan_mode(ndev, features); + } return 0; } @@ -4720,7 +4714,6 @@ static const struct net_device_ops qlge_netdev_ops = { .ndo_set_mac_address = qlge_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = qlge_tx_timeout, - .ndo_fix_features = qlge_fix_features, .ndo_set_features = qlge_set_features, .ndo_vlan_rx_add_vid = qlge_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid, diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index c69b0bdd891d..c1217a87d535 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -371,7 +371,6 @@ struct cpsw_priv { spinlock_t lock; struct platform_device *pdev; struct net_device *ndev; - struct device_node *phy_node; struct napi_struct napi_rx; struct napi_struct napi_tx; struct device *dev; @@ -1165,25 +1164,34 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); - if (priv->phy_node) - slave->phy = of_phy_connect(priv->ndev, priv->phy_node, + if (slave->data->phy_node) { + slave->phy = of_phy_connect(priv->ndev, slave->data->phy_node, &cpsw_adjust_link, 0, slave->data->phy_if); - else + if (!slave->phy) { + dev_err(priv->dev, "phy \"%s\" not found on slave %d\n", + slave->data->phy_node->full_name, + slave->slave_num); + return; + } + } else { slave->phy = phy_connect(priv->ndev, slave->data->phy_id, &cpsw_adjust_link, slave->data->phy_if); - if (IS_ERR(slave->phy)) { - dev_err(priv->dev, "phy %s not found on slave %d\n", - slave->data->phy_id, slave->slave_num); - slave->phy = NULL; - } else { - dev_info(priv->dev, "phy found : id is : 0x%x\n", - slave->phy->phy_id); - phy_start(slave->phy); - - /* Configure GMII_SEL register */ - cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface, - slave->slave_num); + if (IS_ERR(slave->phy)) { + dev_err(priv->dev, + "phy \"%s\" not found on slave %d, err %ld\n", + slave->data->phy_id, slave->slave_num, + PTR_ERR(slave->phy)); + slave->phy = NULL; + return; + } } + + dev_info(priv->dev, "phy found : id is : 0x%x\n", slave->phy->phy_id); + + phy_start(slave->phy); + + /* Configure GMII_SEL register */ + cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface, slave->slave_num); } static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) @@ -1957,12 +1965,11 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, slave->port_vlan = data->dual_emac_res_vlan; } -static int cpsw_probe_dt(struct cpsw_priv *priv, +static int cpsw_probe_dt(struct cpsw_platform_data *data, struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct device_node *slave_node; - struct cpsw_platform_data *data = &priv->data; int i = 0, ret; u32 prop; @@ -2050,7 +2057,8 @@ static int cpsw_probe_dt(struct cpsw_priv *priv, if (strcmp(slave_node->name, "slave")) continue; - priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0); + slave_data->phy_node = of_parse_phandle(slave_node, + "phy-handle", 0); parp = of_get_property(slave_node, "phy_id", &lenp); if (of_phy_is_fixed_link(slave_node)) { struct device_node *phy_node; @@ -2087,6 +2095,7 @@ static int cpsw_probe_dt(struct cpsw_priv *priv, } snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), PHY_ID_FMT, mdio->name, phyid); + put_device(&mdio->dev); } else { dev_err(&pdev->dev, "No slave[%d] phy_id or fixed-link property\n", i); goto no_phy_slave; @@ -2291,7 +2300,7 @@ static int cpsw_probe(struct platform_device *pdev) /* Select default pin state */ pinctrl_pm_select_default_state(&pdev->dev); - if (cpsw_probe_dt(priv, pdev)) { + if (cpsw_probe_dt(&priv->data, pdev)) { dev_err(&pdev->dev, "cpsw: platform data missing\n"); ret = -ENODEV; goto clean_runtime_disable_ret; diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h index 442a7038e660..e50afd1b2eda 100644 --- a/drivers/net/ethernet/ti/cpsw.h +++ b/drivers/net/ethernet/ti/cpsw.h @@ -18,6 +18,7 @@ #include <linux/phy.h> struct cpsw_slave_data { + struct device_node *phy_node; char phy_id[MII_BUS_ID_SIZE]; int phy_if; u8 mac_addr[ETH_ALEN]; diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 6be315303d61..8ecb24186b7f 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -2108,6 +2108,7 @@ static int davinci_emac_remove(struct platform_device *pdev) cpdma_ctlr_destroy(priv->dma); unregister_netdev(ndev); + of_node_put(priv->phy_node); free_netdev(ndev); return 0; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 187b60c8a672..db0476c44b41 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3024,6 +3024,13 @@ static int ath10k_update_channel_list(struct ath10k *ar) passive = channel->flags & IEEE80211_CHAN_NO_IR; ch->passive = passive; + /* the firmware is ignoring the "radar" flag of the + * channel and is scanning actively using Probe Requests + * on "Radar detection"/DFS channels which are not + * marked as "available" + */ + ch->passive |= ch->chan_radar; + ch->freq = channel->center_freq; ch->band_center_freq1 = channel->center_freq; ch->min_power = 0; diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c index 0d46b4f6b6a4..c0810df81bfc 100644 --- a/drivers/net/wireless/cnss2/bus.c +++ b/drivers/net/wireless/cnss2/bus.c @@ -34,6 +34,7 @@ enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id) case QCA6174_DEVICE_ID: case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: return CNSS_BUS_PCI; default: cnss_pr_err("Unknown device_id: 0x%lx\n", device_id); diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h index 4e3d1500bd76..bd32a94e5146 100644 --- a/drivers/net/wireless/cnss2/bus.h +++ b/drivers/net/wireless/cnss2/bus.h @@ -24,6 +24,8 @@ #define QCA6290_DEVICE_ID 0x1100 #define QCA6290_EMULATION_VENDOR_ID 0x168C #define QCA6290_EMULATION_DEVICE_ID 0xABCD +#define QCN7605_VENDOR_ID 0x17CB +#define QCN7605_DEVICE_ID 0x1102 enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev); enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id); diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index acf65e4904d6..ac9d8e7d08ad 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -37,6 +37,7 @@ #define FW_READY_TIMEOUT 20000 #define FW_ASSERT_TIMEOUT 5000 #define CNSS_EVENT_PENDING 2989 +#define CE_MSI_NAME "CE" static struct cnss_plat_data *plat_env; @@ -249,7 +250,7 @@ int cnss_wlan_enable(struct device *dev, { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct wlfw_wlan_cfg_req_msg_v01 req; - u32 i; + u32 i, ce_id, num_vectors, user_base_data, base_vector; int ret = 0; if (plat_priv->device_id == QCA6174_DEVICE_ID) @@ -299,6 +300,19 @@ int cnss_wlan_enable(struct device *dev, req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; } + if (config->num_shadow_reg_cfg) { + req.shadow_reg_valid = 1; + + if (config->num_shadow_reg_cfg > + QMI_WLFW_MAX_NUM_SHADOW_REG_V01) + req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; + else + req.shadow_reg_len = config->num_shadow_reg_cfg; + memcpy(req.shadow_reg, config->shadow_reg_cfg, + sizeof(struct wlfw_shadow_reg_cfg_s_v01) + * req.shadow_reg_len); + } + req.shadow_reg_v2_valid = 1; if (config->num_shadow_reg_v2_cfg > QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01) @@ -310,6 +324,30 @@ int cnss_wlan_enable(struct device *dev, sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) * req.shadow_reg_v2_len); + if (config->rri_over_ddr_cfg_valid) { + req.rri_over_ddr_cfg_valid = 1; + req.rri_over_ddr_cfg.base_addr_low = + config->rri_over_ddr_cfg.base_addr_low; + req.rri_over_ddr_cfg.base_addr_high = + config->rri_over_ddr_cfg.base_addr_high; + } + + if (plat_priv->device_id == QCN7605_DEVICE_ID) { + ret = cnss_get_user_msi_assignment(dev, CE_MSI_NAME, + &num_vectors, + &user_base_data, + &base_vector); + if (!ret) { + req.msi_cfg_valid = 1; + req.msi_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; + for (ce_id = 0; ce_id < QMI_WLFW_MAX_NUM_CE_V01; + ce_id++) { + req.msi_cfg[ce_id].ce_id = ce_id; + req.msi_cfg[ce_id].msi_vector = + (ce_id % num_vectors) + base_vector; + } + } + } ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, &req); if (ret) goto out; @@ -461,6 +499,8 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv) if (ret) goto out; + if (plat_priv->device_id == QCN7605_DEVICE_ID) + goto skip_m3_dnld; ret = cnss_bus_load_m3(plat_priv); if (ret) goto out; @@ -468,7 +508,7 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv) ret = cnss_wlfw_m3_dnld_send_sync(plat_priv); if (ret) goto out; - +skip_m3_dnld: return 0; out: return ret; @@ -1103,7 +1143,10 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv) { plat_priv->cal_done = true; cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01); + if (plat_priv->device_id == QCN7605_DEVICE_ID) + goto skip_shutdown; cnss_bus_dev_shutdown(plat_priv); +skip_shutdown: clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); return 0; @@ -1234,6 +1277,9 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv) case QCA6290_DEVICE_ID: subsys_info->subsys_desc.name = "QCA6290"; break; + case QCN7605_DEVICE_ID: + subsys_info->subsys_desc.name = "QCN7605"; + break; default: cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id); ret = -ENODEV; @@ -1449,6 +1495,7 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv) break; case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: ret = cnss_register_ramdump_v2(plat_priv); break; default: @@ -1537,6 +1584,7 @@ static ssize_t cnss_fs_ready_store(struct device *dev, switch (plat_priv->device_id) { case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: break; default: cnss_pr_err("Not supported for device ID 0x%lx\n", @@ -1599,6 +1647,7 @@ static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv) static const struct platform_device_id cnss_platform_id_table[] = { { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, }, { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, }, + { .name = "qcn7605", .driver_data = QCN7605_DEVICE_ID, }, }; static const struct of_device_id cnss_of_match_table[] = { diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 8f9bc213cac3..427b42c871f3 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -619,6 +619,7 @@ int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv) break; case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: ret = cnss_qca6290_powerup(pci_priv); break; default: @@ -645,6 +646,7 @@ int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv) break; case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: ret = cnss_qca6290_shutdown(pci_priv); break; default: @@ -1295,6 +1297,94 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv) return pm_request_resume(&pci_dev->dev); } +#ifdef CONFIG_CNSS_QCA6390 +int cnss_pci_force_wake_request(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct mhi_controller *mhi_ctrl; + + if (!pci_priv) + return -ENODEV; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return 0; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + read_lock_bh(&mhi_ctrl->pm_lock); + mhi_ctrl->wake_get(mhi_ctrl, true); + read_unlock_bh(&mhi_ctrl->pm_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_request); + +int cnss_pci_is_device_awake(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct mhi_controller *mhi_ctrl; + + if (!pci_priv) + return -ENODEV; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return true; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + return mhi_ctrl->dev_state == MHI_STATE_M0 ? true : false; +} +EXPORT_SYMBOL(cnss_pci_is_device_awake); + +int cnss_pci_force_wake_release(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct mhi_controller *mhi_ctrl; + + if (!pci_priv) + return -ENODEV; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return 0; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + read_lock_bh(&mhi_ctrl->pm_lock); + mhi_ctrl->wake_put(mhi_ctrl, false); + read_unlock_bh(&mhi_ctrl->pm_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_release); +#else +int cnss_pci_force_wake_request(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_request); + +int cnss_pci_is_device_awake(struct device *dev) +{ + return true; +} +EXPORT_SYMBOL(cnss_pci_is_device_awake); + +int cnss_pci_force_wake_release(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_release); +#endif + int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; @@ -2162,6 +2252,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, switch (pci_dev->device) { case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: if (!mhi_is_device_ready(&plat_priv->plat_dev->dev, MHI_NODE_NAME)) { cnss_pr_err("MHI driver is not ready, defer PCI probe!\n"); @@ -2249,6 +2340,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, break; case QCA6290_EMULATION_DEVICE_ID: case QCA6290_DEVICE_ID: + case QCN7605_DEVICE_ID: ret = cnss_pci_enable_msi(pci_priv); if (ret) goto disable_bus; @@ -2324,6 +2416,7 @@ static const struct pci_device_id cnss_pci_id_table[] = { { QCA6290_EMULATION_VENDOR_ID, QCA6290_EMULATION_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, { QCA6290_VENDOR_ID, QCA6290_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID }, + {QCN7605_VENDOR_ID, QCN7605_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID}, { 0 } }; MODULE_DEVICE_TABLE(pci, cnss_pci_id_table); diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c index bbf707b869bd..8f2637c3eaf9 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c @@ -144,6 +144,60 @@ static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { }, }; +static struct elem_info wlfw_rri_over_ddr_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct + wlfw_rri_over_ddr_cfg_s_v01, + base_addr_low), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct + wlfw_rri_over_ddr_cfg_s_v01, + base_addr_high), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_msi_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_msi_cfg_s_v01, + ce_id), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_msi_cfg_s_v01, + msi_vector), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static struct elem_info wlfw_memory_region_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, @@ -922,6 +976,53 @@ struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei, }, { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + rri_over_ddr_cfg_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rri_over_ddr_cfg_s_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + rri_over_ddr_cfg), + .ei_array = wlfw_rri_over_ddr_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + msi_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + msi_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_CE_V01, + .elem_size = sizeof(struct wlfw_msi_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + msi_cfg), + .ei_array = wlfw_msi_cfg_s_v01_ei, + }, + { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h index 00a873d11d14..964c1e56dbdd 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h @@ -170,6 +170,16 @@ struct wlfw_shadow_reg_v2_cfg_s_v01 { u32 addr; }; +struct wlfw_rri_over_ddr_cfg_s_v01 { + u32 base_addr_low; + u32 base_addr_high; +}; + +struct wlfw_msi_cfg_s_v01 { + u16 ce_id; + u16 msi_vector; +}; + struct wlfw_memory_region_info_s_v01 { u64 region_addr; u32 size; @@ -312,6 +322,11 @@ struct wlfw_wlan_cfg_req_msg_v01 { u32 shadow_reg_v2_len; struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01]; + u8 rri_over_ddr_cfg_valid; + struct wlfw_rri_over_ddr_cfg_s_v01 rri_over_ddr_cfg; + u8 msi_cfg_valid; + u32 msi_cfg_len; + struct wlfw_msi_cfg_s_v01 msi_cfg[QMI_WLFW_MAX_NUM_CE_V01]; }; #define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803 diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 13ae5c3c2471..b97e550cba5d 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -2368,6 +2368,12 @@ static void wcnss_nvbin_dnld(void) goto out; } + if (nv->size <= 4) { + pr_err("wcnss: %s: request_firmware failed for %s (file size = %zu)\n", + __func__, NVBIN_FILE, nv->size); + goto out; + } + /* First 4 bytes in nv blob is validity bitmap. * We cannot validate nv, so skip those 4 bytes. */ diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 68d0a5c9d437..3270b4333668 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -86,8 +86,7 @@ struct netfront_cb { /* IRQ name is queue name with "-tx" or "-rx" appended */ #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3) -static DECLARE_WAIT_QUEUE_HEAD(module_load_q); -static DECLARE_WAIT_QUEUE_HEAD(module_unload_q); +static DECLARE_WAIT_QUEUE_HEAD(module_wq); struct netfront_stats { u64 packets; @@ -1336,11 +1335,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); xenbus_switch_state(dev, XenbusStateInitialising); - wait_event(module_load_q, - xenbus_read_driver_state(dev->otherend) != - XenbusStateClosed && - xenbus_read_driver_state(dev->otherend) != - XenbusStateUnknown); + wait_event(module_wq, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown); return netdev; exit: @@ -1608,6 +1607,7 @@ static int xennet_init_queue(struct netfront_queue *queue) { unsigned short i; int err = 0; + char *devid; spin_lock_init(&queue->tx_lock); spin_lock_init(&queue->rx_lock); @@ -1615,8 +1615,9 @@ static int xennet_init_queue(struct netfront_queue *queue) setup_timer(&queue->rx_refill_timer, rx_refill_timeout, (unsigned long)queue); - snprintf(queue->name, sizeof(queue->name), "%s-q%u", - queue->info->netdev->name, queue->id); + devid = strrchr(queue->info->xbdev->nodename, '/') + 1; + snprintf(queue->name, sizeof(queue->name), "vif%s-q%u", + devid, queue->id); /* Initialise tx_skbs as a free chain containing every entry. */ queue->tx_skb_freelist = 0; @@ -2023,15 +2024,14 @@ static void netback_changed(struct xenbus_device *dev, dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state)); + wake_up_all(&module_wq); + switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: - break; - case XenbusStateUnknown: - wake_up_all(&module_unload_q); break; case XenbusStateInitWait: @@ -2047,12 +2047,10 @@ static void netback_changed(struct xenbus_device *dev, break; case XenbusStateClosed: - wake_up_all(&module_unload_q); if (dev->state == XenbusStateClosed) break; /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: - wake_up_all(&module_unload_q); xenbus_frontend_closed(dev); break; } @@ -2160,14 +2158,14 @@ static int xennet_remove(struct xenbus_device *dev) if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) { xenbus_switch_state(dev, XenbusStateClosing); - wait_event(module_unload_q, + wait_event(module_wq, xenbus_read_driver_state(dev->otherend) == XenbusStateClosing || xenbus_read_driver_state(dev->otherend) == XenbusStateUnknown); xenbus_switch_state(dev, XenbusStateClosed); - wait_event(module_unload_q, + wait_event(module_wq, xenbus_read_driver_state(dev->otherend) == XenbusStateClosed || xenbus_read_driver_state(dev->otherend) == diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 01cf1c1a841a..8de329546b82 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -286,12 +286,16 @@ static int bpp_probe(struct platform_device *op) ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations), GFP_KERNEL); - if (!ops) + if (!ops) { + err = -ENOMEM; goto out_unmap; + } dprintk(("register_port\n")); - if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) + if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) { + err = -ENOMEM; goto out_free_ops; + } p->size = size; p->dev = &op->dev; diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 379d08f76146..d0a4652bb9ac 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -1235,7 +1235,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.end = min_t(resource_size_t, IO_SPACE_LIMIT, - resource_size(&pcie->io)); + resource_size(&pcie->io) - 1); } else pcie->realio = pcie->io; diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c index 4dbb4cae2fae..9796bdc7534e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm660.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -92,6 +92,31 @@ .intr_detection_bit = -1, \ .intr_detection_width = -1, \ } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } static const struct pinctrl_pin_desc sdm660_pins[] = { PINCTRL_PIN(0, "GPIO_0"), PINCTRL_PIN(1, "GPIO_1"), @@ -214,6 +239,7 @@ static const struct pinctrl_pin_desc sdm660_pins[] = { PINCTRL_PIN(118, "SDC2_CMD"), PINCTRL_PIN(119, "SDC2_DATA"), PINCTRL_PIN(120, "SDC1_RCLK"), + PINCTRL_PIN(121, "UFS_RESET"), }; #define DECLARE_MSM_GPIO_PINS(pin) \ @@ -340,6 +366,7 @@ static const unsigned int sdc2_clk_pins[] = { 117 }; static const unsigned int sdc2_cmd_pins[] = { 118 }; static const unsigned int sdc2_data_pins[] = { 119 }; static const unsigned int sdc1_rclk_pins[] = { 120 }; +static const unsigned int ufs_reset_pins[] = { 121 }; enum sdm660_functions { msm_mux_blsp_spi1, @@ -1673,6 +1700,7 @@ static const struct msm_pingroup sdm660_groups[] = { SDC_QDSD_PINGROUP(sdc2_cmd, 0x99b000, 11, 3), SDC_QDSD_PINGROUP(sdc2_data, 0x99b000, 9, 0), SDC_QDSD_PINGROUP(sdc1_rclk, 0x99a000, 15, 0), + UFS_RESET(ufs_reset, 0x9a3000), }; static const struct msm_pinctrl_soc_data sdm660_pinctrl = { diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 9753fbb596cf..069d167ab410 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -411,31 +411,47 @@ static int pmic_gpio_config_get(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_DRIVE_PUSH_PULL: - arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS; + if (pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; + if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_DRIVE_OPEN_SOURCE: - arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; + if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_DOWN: - arg = pad->pullup == PMIC_GPIO_PULL_DOWN; + if (pad->pullup != PMIC_GPIO_PULL_DOWN) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_DISABLE: - arg = pad->pullup = PMIC_GPIO_PULL_DISABLE; + if (pad->pullup != PMIC_GPIO_PULL_DISABLE) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_UP: - arg = pad->pullup == PMIC_GPIO_PULL_UP_30; + if (pad->pullup != PMIC_GPIO_PULL_UP_30) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: - arg = !pad->is_enabled; + if (pad->is_enabled) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_POWER_SOURCE: arg = pad->power_source; break; case PIN_CONFIG_INPUT_ENABLE: - arg = pad->input_enabled; + if (!pad->input_enabled) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_OUTPUT: arg = pad->out_value; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index a260dbe010f3..8f6024c51e1d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -1047,13 +1047,12 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, goto error; } /* - * do not allow any rules to be added at end of the "default" routing - * tables + * do not allow any rule to be added at "default" routing + * table */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && - (tbl->rule_cnt > 0) && (at_rear != 0)) { - IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d at_rear=%d" - , tbl->rule_cnt, at_rear); + (tbl->rule_cnt > 0)) { + IPAERR_RL("cannot add rules to default rt table\n"); goto error; } @@ -1275,13 +1274,12 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) } /* - * do not allow any rules to be added at end of the "default" routing - * tables + * do not allow any rule to be added at "default" routing + * table */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && - (&entry->link == tbl->head_rt_rule_list.prev)) { - IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d\n", - tbl->rule_cnt); + (tbl->rule_cnt > 0)) { + IPAERR_RL("cannot add rules to default rt table\n"); ret = -EINVAL; goto bail; } @@ -1740,6 +1738,10 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) goto error; } + if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) { + IPAERR_RL("Default tbl rule cannot be modified\n"); + return -EINVAL; + } /* Adding check to confirm still * header entry present in header table or not */ diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 0e0403e024c5..852d2de7f69f 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -392,6 +392,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ + { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_END, 0}, }; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index f774cb576ffa..1ff95b5a429d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -34,6 +34,7 @@ #define TOSHIBA_ACPI_VERSION "0.23" #define PROC_INTERFACE_VERSION 1 +#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -1472,7 +1473,7 @@ static const struct file_operations keys_proc_fops = { .write = keys_proc_write, }; -static int version_proc_show(struct seq_file *m, void *v) +static int __maybe_unused version_proc_show(struct seq_file *m, void *v) { seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index bd170cb3361c..5747a54cbd42 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -164,6 +164,10 @@ static int bq4802_probe(struct platform_device *pdev) } else if (p->r->flags & IORESOURCE_MEM) { p->regs = devm_ioremap(&pdev->dev, p->r->start, resource_size(p->r)); + if (!p->regs){ + err = -ENOMEM; + goto out; + } p->read = bq4802_read_mem; p->write = bq4802_write_mem; } else { diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 21d174e9ebdb..dac2f6883e28 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2101,8 +2101,11 @@ static int dasd_eckd_basic_to_ready(struct dasd_device *device) static int dasd_eckd_online_to_ready(struct dasd_device *device) { - cancel_work_sync(&device->reload_device); - cancel_work_sync(&device->kick_validate); + if (cancel_work_sync(&device->reload_device)) + dasd_put_device(device); + if (cancel_work_sync(&device->kick_validate)) + dasd_put_device(device); + return 0; }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 95c631125a20..09ac56317f1b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3505,13 +3505,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (atomic_read(&queue->set_pci_flags_count)) qdio_flags |= QDIO_FLAG_PCI_OUT; + atomic_add(count, &queue->used_buffers); + rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, queue->queue_no, index, count); if (queue->card->options.performance_stats) queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; - atomic_add(count, &queue->used_buffers); if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index fa844b0ff847..7bcf0dae3a65 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -419,6 +419,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (card->discipline) { card->discipline->remove(card->gdev); qeth_core_free_discipline(card); + card->options.layer2 = -1; } rc = qeth_core_load_discipline(card, newdis); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 5466246c69b4..b78a2f3745f2 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -2045,6 +2045,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twa_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2067,6 +2068,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = ioremap(mem_addr, mem_len); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -2074,8 +2076,10 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) TW_DISABLE_INTERRUPTS(tw_dev); /* Initialize the card */ - if (twa_reset_sequence(tw_dev, 0)) + if (twa_reset_sequence(tw_dev, 0)) { + retval = -ENOMEM; goto out_iounmap; + } /* Set host specific parameters */ if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) || diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index f8374850f714..f0a5536a9ff5 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1600,6 +1600,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twl_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -1614,6 +1615,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = pci_iomap(pdev, 1, 0); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -1623,6 +1625,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) /* Initialize the card */ if (twl_reset_sequence(tw_dev, 0)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe"); + retval = -ENOMEM; goto out_iounmap; } diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 14af38036287..308a4206b636 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2278,6 +2278,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (tw_initialize_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension."); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2292,6 +2293,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = pci_resource_start(pdev, 0); if (!tw_dev->base_addr) { printk(KERN_WARNING "3w-xxxx: Failed to get io address."); + retval = -ENOMEM; goto out_release_mem_region; } diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 662b2321d1b0..913ebb6d0d29 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -1031,8 +1031,10 @@ static int __init aic94xx_init(void) aic94xx_transport_template = sas_domain_attach_transport(&aic94xx_transport_functions); - if (!aic94xx_transport_template) + if (!aic94xx_transport_template) { + err = -ENOMEM; goto out_destroy_caches; + } err = pci_register_driver(&aic94xx_pci_driver); if (err) diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index 65935f6eb48f..5b84a57423b9 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -117,7 +117,7 @@ void hab_ctx_free(struct kref *ref) struct export_desc *exp, *exp_tmp; /* garbage-collect exp/imp buffers */ - write_lock(&ctx->exp_lock); + write_lock_bh(&ctx->exp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->exp_whse, node) { list_del(&exp->node); pr_debug("potential leak exp %d vcid %X recovered\n", @@ -125,7 +125,7 @@ void hab_ctx_free(struct kref *ref) habmem_hyp_revoke(exp->payload, exp->payload_count); habmem_remove_export(exp); } - write_unlock(&ctx->exp_lock); + write_unlock_bh(&ctx->exp_lock); spin_lock_bh(&ctx->imp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) { @@ -159,27 +159,27 @@ void hab_ctx_free(struct kref *ref) ctx->kernel, ctx->closing, ctx->owner); /* check vchans in this ctx */ - write_lock(&ctx->ctx_lock); + write_lock_bh(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { pr_warn("leak vchan id %X cnt %X remote %d in ctx\n", vchan->id, get_refcnt(vchan->refcount), vchan->otherend_id); } - write_unlock(&ctx->ctx_lock); + write_unlock_bh(&ctx->ctx_lock); /* check pending open */ if (ctx->pending_cnt) pr_warn("potential leak of pendin_open nodes %d\n", ctx->pending_cnt); - write_lock(&ctx->ctx_lock); + write_lock_bh(&ctx->ctx_lock); list_for_each_entry(node, &ctx->pending_open, node) { pr_warn("leak pending open vcid %X type %d subid %d openid %d\n", node->request.xdata.vchan_id, node->request.type, node->request.xdata.sub_id, node->request.xdata.open_id); } - write_unlock(&ctx->ctx_lock); + write_unlock_bh(&ctx->ctx_lock); /* check vchans belong to this ctx in all hab/mmid devices */ for (i = 0; i < hab_driver.ndevices; i++) { @@ -218,7 +218,15 @@ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { if (vcid == vchan->id) { - kref_get(&vchan->refcount); + if (vchan->otherend_closed || vchan->closed || + !kref_get_unless_zero(&vchan->refcount)) { + pr_debug("failed to inc vcid %x remote %x session %d refcnt %d close_flg remote %d local %d\n", + vchan->id, vchan->otherend_id, + vchan->session_id, + get_refcnt(vchan->refcount), + vchan->otherend_closed, vchan->closed); + vchan = NULL; + } read_unlock(&ctx->ctx_lock); return vchan; } diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c index da41536205a5..60156c6b00f0 100644 --- a/drivers/soc/qcom/hab/hab_mem_linux.c +++ b/drivers/soc/qcom/hab/hab_mem_linux.c @@ -21,17 +21,14 @@ struct pages_list { struct page **pages; long npages; uint64_t index; /* for mmap first call */ - int kernel; void *kva; - void *uva; - int refcntk; - int refcntu; uint32_t userflags; struct file *filp_owner; struct file *filp_mapper; - struct dma_buf *dmabuf; int32_t export_id; int32_t vcid; + struct physical_channel *pchan; + struct kref refcount; }; struct importer_context { @@ -41,6 +38,118 @@ struct importer_context { rwlock_t implist_lock; }; +static struct pages_list *pages_list_create( + void *imp_ctx, + struct export_desc *exp, + uint32_t userflags) +{ + struct page **pages; + struct compressed_pfns *pfn_table = + (struct compressed_pfns *)exp->payload; + struct pages_list *pglist; + unsigned long pfn; + int i, j, k = 0, size; + + if (!pfn_table) + return ERR_PTR(-EINVAL); + + size = exp->payload_count * sizeof(struct page *); + pages = kmalloc(size, GFP_KERNEL); + if (!pages) + return ERR_PTR(-ENOMEM); + + pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); + if (!pglist) { + kfree(pages); + return ERR_PTR(-ENOMEM); + } + + pfn = pfn_table->first_pfn; + for (i = 0; i < pfn_table->nregions; i++) { + for (j = 0; j < pfn_table->region[i].size; j++) { + pages[k] = pfn_to_page(pfn+j); + k++; + } + pfn += pfn_table->region[i].size + pfn_table->region[i].space; + } + + pglist->pages = pages; + pglist->npages = exp->payload_count; + pglist->userflags = userflags; + pglist->export_id = exp->export_id; + pglist->vcid = exp->vcid_remote; + pglist->pchan = exp->pchan; + + kref_init(&pglist->refcount); + + return pglist; +} + +static void pages_list_destroy(struct kref *refcount) +{ + struct pages_list *pglist = container_of(refcount, + struct pages_list, refcount); + + if (pglist->kva) + vunmap(pglist->kva); + + kfree(pglist->pages); + + kfree(pglist); +} + +static void pages_list_get(struct pages_list *pglist) +{ + kref_get(&pglist->refcount); +} + +static int pages_list_put(struct pages_list *pglist) +{ + return kref_put(&pglist->refcount, pages_list_destroy); +} + +static struct pages_list *pages_list_lookup( + struct importer_context *imp_ctx, + uint32_t export_id, struct physical_channel *pchan) +{ + struct pages_list *pglist, *tmp; + + read_lock(&imp_ctx->implist_lock); + list_for_each_entry_safe(pglist, tmp, &imp_ctx->imp_list, list) { + if (pglist->export_id == export_id && + pglist->pchan == pchan) { + pages_list_get(pglist); + read_unlock(&imp_ctx->implist_lock); + return pglist; + } + } + read_unlock(&imp_ctx->implist_lock); + + return NULL; +} + +static void pages_list_add(struct importer_context *imp_ctx, + struct pages_list *pglist) +{ + pages_list_get(pglist); + + write_lock(&imp_ctx->implist_lock); + list_add_tail(&pglist->list, &imp_ctx->imp_list); + imp_ctx->cnt++; + write_unlock(&imp_ctx->implist_lock); +} + +static void pages_list_remove(struct importer_context *imp_ctx, + struct pages_list *pglist) +{ + write_lock(&imp_ctx->implist_lock); + list_del(&pglist->list); + imp_ctx->cnt--; + write_unlock(&imp_ctx->implist_lock); + + pages_list_put(pglist); +} + void *habmm_hyp_allocate_grantable(int page_count, uint32_t *sizebytes) { @@ -79,6 +188,7 @@ static int habmem_get_dma_pages_from_va(unsigned long address, vma = find_vma(current->mm, address); if (!vma || !vma->vm_file) { pr_err("cannot find vma\n"); + rc = -EBADF; goto err; } @@ -86,6 +196,7 @@ static int habmem_get_dma_pages_from_va(unsigned long address, fd = iterate_fd(current->files, 0, match_file, vma->vm_file); if (fd == 0) { pr_err("iterate_fd failed\n"); + rc = -EBADF; goto err; } @@ -93,10 +204,16 @@ static int habmem_get_dma_pages_from_va(unsigned long address, page_offset = offset/PAGE_SIZE; dmabuf = dma_buf_get(fd - 1); + if (IS_ERR_OR_NULL(dmabuf)) { + pr_err("dma_buf_get failed fd %d ret %pK\n", fd, dmabuf); + rc = -EBADF; + goto err; + } attach = dma_buf_attach(dmabuf, hab_driver.dev); if (IS_ERR_OR_NULL(attach)) { pr_err("dma_buf_attach failed\n"); + rc = -EBADF; goto err; } @@ -104,6 +221,7 @@ static int habmem_get_dma_pages_from_va(unsigned long address, if (IS_ERR_OR_NULL(sg_table)) { pr_err("dma_buf_map_attachment failed\n"); + rc = -EBADF; goto err; } @@ -154,12 +272,16 @@ static int habmem_get_dma_pages_from_fd(int32_t fd, int i, j, rc = 0; dmabuf = dma_buf_get(fd); - if (IS_ERR(dmabuf)) - return PTR_ERR(dmabuf); + if (IS_ERR_OR_NULL(dmabuf)) { + pr_err("dma_buf_get failed fd %d ret %pK\n", fd, dmabuf); + rc = -EBADF; + goto err; + } attach = dma_buf_attach(dmabuf, hab_driver.dev); if (IS_ERR_OR_NULL(attach)) { pr_err("dma_buf_attach failed\n"); + rc = -EBADF; goto err; } @@ -167,6 +289,7 @@ static int habmem_get_dma_pages_from_fd(int32_t fd, if (IS_ERR_OR_NULL(sg_table)) { pr_err("dma_buf_map_attachment failed\n"); + rc = -EBADF; goto err; } @@ -177,9 +300,12 @@ static int habmem_get_dma_pages_from_fd(int32_t fd, for (j = 0; j < (s->length >> PAGE_SHIFT); j++) { pages[rc] = nth_page(page, j); rc++; - if (WARN_ON(rc >= page_count)) + if (rc >= page_count) break; } + + if (rc >= page_count) + break; } err: @@ -305,16 +431,8 @@ void habmem_imp_hyp_close(void *imp_ctx, int kernel) if (!priv) return; - list_for_each_entry_safe(pglist, pglist_tmp, &priv->imp_list, list) { - if (kernel && pglist->kva) - vunmap(pglist->kva); - - list_del(&pglist->list); - priv->cnt--; - - kfree(pglist->pages); - kfree(pglist); - } + list_for_each_entry_safe(pglist, pglist_tmp, &priv->imp_list, list) + pages_list_remove(priv, pglist); kfree(priv); } @@ -391,10 +509,19 @@ static int hab_map_fault(struct vm_area_struct *vma, struct vm_fault *vmf) static void hab_map_open(struct vm_area_struct *vma) { + struct pages_list *pglist = + (struct pages_list *)vma->vm_private_data; + + pages_list_get(pglist); } static void hab_map_close(struct vm_area_struct *vma) { + struct pages_list *pglist = + (struct pages_list *)vma->vm_private_data; + + pages_list_put(pglist); + vma->vm_private_data = NULL; } static const struct vm_operations_struct habmem_vm_ops = { @@ -403,6 +530,51 @@ static const struct vm_operations_struct habmem_vm_ops = { .close = hab_map_close, }; +static int hab_buffer_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct pages_list *pglist = vma->vm_private_data; + pgoff_t page_offset; + int ret; + + page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> + PAGE_SHIFT; + + if (page_offset > pglist->npages) + return VM_FAULT_SIGBUS; + + ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, + pglist->pages[page_offset]); + + switch (ret) { + case 0: + return VM_FAULT_NOPAGE; + case -ENOMEM: + return VM_FAULT_OOM; + case -EBUSY: + return VM_FAULT_RETRY; + case -EFAULT: + case -EINVAL: + return VM_FAULT_SIGBUS; + default: + WARN_ON(1); + return VM_FAULT_SIGBUS; + } +} + +static void hab_buffer_open(struct vm_area_struct *vma) +{ +} + +static void hab_buffer_close(struct vm_area_struct *vma) +{ +} + +static const struct vm_operations_struct hab_buffer_vm_ops = { + .fault = hab_buffer_fault, + .open = hab_buffer_open, + .close = hab_buffer_close, +}; + static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) { struct pages_list *pglist = dmabuf->priv; @@ -416,7 +588,7 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = &habmem_vm_ops; + vma->vm_ops = &hab_buffer_vm_ops; vma->vm_private_data = pglist; vma->vm_flags |= VM_MIXEDMAP; @@ -425,6 +597,9 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) static void hab_mem_dma_buf_release(struct dma_buf *dmabuf) { + struct pages_list *pglist = dmabuf->priv; + + pages_list_put(pglist); } static void *hab_mem_dma_buf_kmap(struct dma_buf *dmabuf, @@ -455,81 +630,50 @@ static int habmem_imp_hyp_map_fd(void *imp_ctx, uint32_t userflags, int32_t *pfd) { - struct page **pages; - struct compressed_pfns *pfn_table = - (struct compressed_pfns *)exp->payload; struct pages_list *pglist; struct importer_context *priv = imp_ctx; - unsigned long pfn; - int i, j, k = 0; - pgprot_t prot = PAGE_KERNEL; - int32_t fd, size; + int32_t fd = -1; int ret; + struct dma_buf *dmabuf; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); - if (!pfn_table || !priv) + if (!priv) return -EINVAL; - size = exp->payload_count * sizeof(struct page *); - pages = kmalloc(size, GFP_KERNEL); - if (!pages) - return -ENOMEM; - - pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); - if (!pglist) { - kfree(pages); - return -ENOMEM; - } - pfn = pfn_table->first_pfn; - for (i = 0; i < pfn_table->nregions; i++) { - for (j = 0; j < pfn_table->region[i].size; j++) { - pages[k] = pfn_to_page(pfn+j); - k++; - } - pfn += pfn_table->region[i].size + pfn_table->region[i].space; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) + goto buffer_ready; - pglist->pages = pages; - pglist->npages = exp->payload_count; - pglist->kernel = 0; - pglist->index = 0; - pglist->refcntk = pglist->refcntu = 0; - pglist->userflags = userflags; - pglist->export_id = exp->export_id; - pglist->vcid = exp->vcid_remote; + pglist = pages_list_create(imp_ctx, exp, userflags); + if (IS_ERR(pglist)) + return PTR_ERR(pglist); - if (!(userflags & HABMM_IMPORT_FLAGS_CACHED)) - prot = pgprot_writecombine(prot); + pages_list_add(priv, pglist); +buffer_ready: exp_info.ops = &dma_buf_ops; - exp_info.size = exp->payload_count << PAGE_SHIFT; + exp_info.size = pglist->npages << PAGE_SHIFT; exp_info.flags = O_RDWR; exp_info.priv = pglist; - pglist->dmabuf = dma_buf_export(&exp_info); - if (IS_ERR(pglist->dmabuf)) { - ret = PTR_ERR(pglist->dmabuf); - kfree(pages); - kfree(pglist); - return ret; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + pr_err("export to dmabuf failed\n"); + ret = PTR_ERR(dmabuf); + goto proc_end; } + pages_list_get(pglist); - fd = dma_buf_fd(pglist->dmabuf, O_CLOEXEC); + fd = dma_buf_fd(dmabuf, O_CLOEXEC); if (fd < 0) { - dma_buf_put(pglist->dmabuf); - kfree(pages); - kfree(pglist); - return -EINVAL; + pr_err("dma buf to fd failed\n"); + dma_buf_put(dmabuf); + ret = -EINVAL; + goto proc_end; } - pglist->refcntk++; - - write_lock(&priv->implist_lock); - list_add_tail(&pglist->list, &priv->imp_list); - priv->cnt++; - write_unlock(&priv->implist_lock); - +proc_end: *pfd = fd; - + pages_list_put(pglist); return 0; } @@ -538,67 +682,45 @@ static int habmem_imp_hyp_map_kva(void *imp_ctx, uint32_t userflags, void **pkva) { - struct page **pages; - struct compressed_pfns *pfn_table = - (struct compressed_pfns *)exp->payload; struct pages_list *pglist; struct importer_context *priv = imp_ctx; - unsigned long pfn; - int i, j, k = 0, size; pgprot_t prot = PAGE_KERNEL; - if (!pfn_table || !priv) + if (!priv) return -EINVAL; - size = exp->payload_count * sizeof(struct page *); - pages = kmalloc(size, GFP_KERNEL); - if (!pages) - return -ENOMEM; - pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); - if (!pglist) { - kfree(pages); - return -ENOMEM; - } - pfn = pfn_table->first_pfn; - for (i = 0; i < pfn_table->nregions; i++) { - for (j = 0; j < pfn_table->region[i].size; j++) { - pages[k] = pfn_to_page(pfn+j); - k++; - } - pfn += pfn_table->region[i].size + pfn_table->region[i].space; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) + goto buffer_ready; - pglist->pages = pages; - pglist->npages = exp->payload_count; - pglist->kernel = 1; - pglist->refcntk = pglist->refcntu = 0; - pglist->userflags = userflags; - pglist->export_id = exp->export_id; - pglist->vcid = exp->vcid_remote; + pglist = pages_list_create(imp_ctx, exp, userflags); + if (IS_ERR(pglist)) + return PTR_ERR(pglist); + + pages_list_add(priv, pglist); + +buffer_ready: + if (pglist->kva) + goto pro_end; + + if (pglist->userflags != userflags) { + pr_info("exp %d: userflags: 0x%x -> 0x%x\n", + exp->export_id, pglist->userflags, userflags); + pglist->userflags = userflags; + } if (!(userflags & HABMM_IMPORT_FLAGS_CACHED)) prot = pgprot_writecombine(prot); pglist->kva = vmap(pglist->pages, pglist->npages, VM_MAP, prot); if (pglist->kva == NULL) { - kfree(pages); pr_err("%ld pages vmap failed\n", pglist->npages); - kfree(pglist); return -ENOMEM; } - pr_debug("%ld pages vmap pass, return %p\n", - pglist->npages, pglist->kva); - - pglist->refcntk++; - - write_lock(&priv->implist_lock); - list_add_tail(&pglist->list, &priv->imp_list); - priv->cnt++; - write_unlock(&priv->implist_lock); - +pro_end: *pkva = pglist->kva; - + pages_list_put(pglist); return 0; } @@ -607,51 +729,31 @@ static int habmem_imp_hyp_map_uva(void *imp_ctx, uint32_t userflags, uint64_t *index) { - struct page **pages; - struct compressed_pfns *pfn_table = - (struct compressed_pfns *)exp->payload; struct pages_list *pglist; struct importer_context *priv = imp_ctx; - unsigned long pfn; - int i, j, k = 0, size; - if (!pfn_table || !priv) + if (!priv) return -EINVAL; - size = exp->payload_count * sizeof(struct page *); - pages = kmalloc(size, GFP_KERNEL); - if (!pages) - return -ENOMEM; - pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); - if (!pglist) { - kfree(pages); - return -ENOMEM; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) + goto buffer_ready; - pfn = pfn_table->first_pfn; - for (i = 0; i < pfn_table->nregions; i++) { - for (j = 0; j < pfn_table->region[i].size; j++) { - pages[k] = pfn_to_page(pfn+j); - k++; - } - pfn += pfn_table->region[i].size + pfn_table->region[i].space; - } + pglist = pages_list_create(imp_ctx, exp, userflags); + if (IS_ERR(pglist)) + return PTR_ERR(pglist); - pglist->pages = pages; - pglist->npages = exp->payload_count; - pglist->index = page_to_phys(pages[0]) >> PAGE_SHIFT; - pglist->refcntk = pglist->refcntu = 0; - pglist->userflags = userflags; - pglist->export_id = exp->export_id; - pglist->vcid = exp->vcid_remote; + pages_list_add(priv, pglist); - write_lock(&priv->implist_lock); - list_add_tail(&pglist->list, &priv->imp_list); - priv->cnt++; - write_unlock(&priv->implist_lock); +buffer_ready: + if (pglist->index) + goto proc_end; - *index = pglist->index << PAGE_SHIFT; + pglist->index = page_to_phys(pglist->pages[0]) >> PAGE_SHIFT; +proc_end: + *index = pglist->index << PAGE_SHIFT; + pages_list_put(pglist); return 0; } @@ -679,37 +781,17 @@ int habmem_imp_hyp_map(void *imp_ctx, struct hab_import *param, int habmm_imp_hyp_unmap(void *imp_ctx, struct export_desc *exp, int kernel) { struct importer_context *priv = imp_ctx; - struct pages_list *pglist, *tmp; - int found = 0; - - write_lock(&priv->implist_lock); - list_for_each_entry_safe(pglist, tmp, &priv->imp_list, list) { - if (pglist->export_id == exp->export_id && - pglist->vcid == exp->vcid_remote) { - found = 1; - list_del(&pglist->list); - priv->cnt--; - break; - } - } - write_unlock(&priv->implist_lock); + struct pages_list *pglist; - if (!found) { + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (!pglist) { pr_err("failed to find export id %u\n", exp->export_id); return -EINVAL; } - pr_debug("detach pglist %p, kernel %d, list cnt %d\n", - pglist, pglist->kernel, priv->cnt); + pages_list_remove(priv, pglist); - if (pglist->kva) - vunmap(pglist->kva); - - if (pglist->dmabuf) - dma_buf_put(pglist->dmabuf); - - kfree(pglist->pages); - kfree(pglist); + pages_list_put(pglist); return 0; } @@ -721,11 +803,14 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) long length = vma->vm_end - vma->vm_start; struct pages_list *pglist; int bfound = 0; + int ret = 0; read_lock(&imp_ctx->implist_lock); list_for_each_entry(pglist, &imp_ctx->imp_list, list) { - if (pglist->index == vma->vm_pgoff) { + if ((pglist->index == vma->vm_pgoff) && + ((length <= pglist->npages * PAGE_SIZE))) { bfound = 1; + pages_list_get(pglist); break; } } @@ -739,7 +824,8 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) if (length > pglist->npages * PAGE_SIZE) { pr_err("Error vma length %ld not matching page list %ld\n", length, pglist->npages * PAGE_SIZE); - return -EINVAL; + ret = -EINVAL; + goto proc_end; } vma->vm_ops = &habmem_vm_ops; @@ -750,6 +836,10 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); return 0; + +proc_end: + pages_list_put(pglist); + return ret; } int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp) @@ -758,15 +848,11 @@ int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp) struct pages_list *pglist; int found = 0; - read_lock(&priv->implist_lock); - list_for_each_entry(pglist, &priv->imp_list, list) { - if (pglist->export_id == exp->export_id && - pglist->vcid == exp->vcid_remote) { - found = 1; - break; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) { + found = 1; + pages_list_put(pglist); } - read_unlock(&priv->implist_lock); return found; } diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c index 23087680c690..d5786170f0f3 100644 --- a/drivers/soc/qcom/hab/hab_mimex.c +++ b/drivers/soc/qcom/hab/hab_mimex.c @@ -319,8 +319,7 @@ int hab_mem_unexport(struct uhab_context *ctx, write_lock(&ctx->exp_lock); list_for_each_entry_safe(exp, tmp, &ctx->exp_whse, node) { if (param->exportid == exp->export_id && - param->vcid == exp->vcid_local) { - /* same vchan guarantees the pchan for idr */ + vchan->pchan == exp->pchan) { list_del(&exp->node); found = 1; break; @@ -367,10 +366,7 @@ int hab_mem_import(struct uhab_context *ctx, spin_lock_bh(&ctx->imp_lock); list_for_each_entry(exp, &ctx->imp_whse, node) { if ((exp->export_id == param->exportid) && - (param->vcid == exp->vcid_remote)) { - /* only allow import on the vchan recevied from - * remote - */ + (exp->pchan == vchan->pchan)) { found = 1; break; } @@ -424,8 +420,8 @@ int hab_mem_unimport(struct uhab_context *ctx, spin_lock_bh(&ctx->imp_lock); list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) { if (exp->export_id == param->exportid && - param->vcid == exp->vcid_remote) { - /* same vchan is expected here */ + exp->pchan == vchan->pchan) { + /* same pchan is expected here */ list_del(&exp->node); ctx->import_total--; found = 1; diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c index 9d5ee134c94e..3765623d3190 100644 --- a/drivers/soc/qcom/hab/hab_msg.c +++ b/drivers/soc/qcom/hab/hab_msg.c @@ -282,6 +282,7 @@ int hab_msg_recv(struct physical_channel *pchan, } exp_desc->domid_local = pchan->dom_id; + exp_desc->pchan = pchan; hab_export_enqueue(vchan, exp_desc); hab_send_export_ack(vchan, pchan, exp_desc); diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c index e7b46df3f97e..d572e4c8a34b 100644 --- a/drivers/soc/qcom/hab/hab_vchan.c +++ b/drivers/soc/qcom/hab/hab_vchan.c @@ -90,7 +90,7 @@ hab_vchan_free(struct kref *ref) vchan->ctx = NULL; /* release vchan from pchan. no more msg for this vchan */ - write_lock(&pchan->vchans_lock); + write_lock_bh(&pchan->vchans_lock); list_for_each_entry_safe(vc, vc_tmp, &pchan->vchannels, pnode) { if (vchan == vc) { list_del(&vc->pnode); @@ -99,7 +99,7 @@ hab_vchan_free(struct kref *ref) break; } } - write_unlock(&pchan->vchans_lock); + write_unlock_bh(&pchan->vchans_lock); /* release idr at the last so same idr will not be used early */ spin_lock_bh(&pchan->vid_lock); @@ -144,6 +144,13 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) get_refcnt(vchan->refcount), payload_type, sizebytes); vchan = NULL; + } else if (vchan->otherend_closed || vchan->closed) { + pr_err("closed already remote %d local %d vcid %x remote %x session %d refcnt %d header %x session %d type %d sz %zd\n", + vchan->otherend_closed, vchan->closed, + vchan->id, vchan->otherend_id, + vchan->session_id, get_refcnt(vchan->refcount), + vchan_id, session_id, payload_type, sizebytes); + vchan = NULL; } else if (!kref_get_unless_zero(&vchan->refcount)) { /* * this happens when refcnt is already zero @@ -154,13 +161,6 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) vchan->session_id, get_refcnt(vchan->refcount), vchan_id, session_id, payload_type, sizebytes); vchan = NULL; - } else if (vchan->otherend_closed || vchan->closed) { - pr_err("closed already remote %d local %d vcid %x remote %x session %d refcnt %d header %x session %d type %d sz %zd\n", - vchan->otherend_closed, vchan->closed, - vchan->id, vchan->otherend_id, - vchan->session_id, get_refcnt(vchan->refcount), - vchan_id, session_id, payload_type, sizebytes); - vchan = NULL; } } spin_unlock_bh(&pchan->vid_lock); @@ -262,7 +262,7 @@ static void hab_vchan_schedule_free(struct kref *ref) * similar logic is in ctx free. if ctx free runs first, * this is skipped */ - write_lock(&ctx->ctx_lock); + write_lock_bh(&ctx->ctx_lock); list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { if (vchan == vchanin) { pr_debug("vchan free refcnt = %d\n", @@ -273,7 +273,7 @@ static void hab_vchan_schedule_free(struct kref *ref) break; } } - write_unlock(&ctx->ctx_lock); + write_unlock_bh(&ctx->ctx_lock); if (bnotify) hab_vchan_stop_notify(vchan); diff --git a/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c b/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c index 75b114e6905c..95562d2cbfad 100644 --- a/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c +++ b/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c @@ -53,8 +53,6 @@ struct anc_tdm_group_set_info { struct anc_dev_drv_info { uint32_t state; - uint32_t rpm; - uint32_t bypass_mode; uint32_t algo_module_id; }; @@ -311,52 +309,68 @@ static int anc_dev_port_stop(int32_t which_port) int msm_anc_dev_set_info(void *info_p, int32_t anc_cmd) { - int rc = 0; + int rc = -EINVAL; switch (anc_cmd) { - case ANC_CMD_RPM: { - struct audio_anc_rpm_info *rpm_info_p = - (struct audio_anc_rpm_info *)info_p; + case ANC_CMD_ALGO_MODULE: { + struct audio_anc_algo_module_info *module_info_p = + (struct audio_anc_algo_module_info *)info_p; + + rc = 0; if (this_anc_dev_info.state) - rc = anc_if_set_rpm( + rc = anc_if_set_algo_module_id( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - rpm_info_p->rpm); + module_info_p->module_id); else - this_anc_dev_info.rpm = 0; + this_anc_dev_info.algo_module_id = + module_info_p->module_id; break; } - case ANC_CMD_BYPASS_MODE: { - struct audio_anc_bypass_mode *bypass_mode_p = - (struct audio_anc_bypass_mode *)info_p; - + case ANC_CMD_ALGO_CALIBRATION: { + rc = -EINVAL; if (this_anc_dev_info.state) - rc = anc_if_set_bypass_mode( + rc = anc_if_set_algo_module_cali_data( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - bypass_mode_p->mode); + info_p); else - this_anc_dev_info.bypass_mode = bypass_mode_p->mode; + pr_err("%s: ANC is not running yet\n", + __func__); + break; + } + default: + pr_err("%s: ANC cmd wrong\n", + __func__); break; } - case ANC_CMD_ALGO_MODULE: { - struct audio_anc_algo_module_info *module_info_p = - (struct audio_anc_algo_module_info *)info_p; + return rc; +} + +int msm_anc_dev_get_info(void *info_p, int32_t anc_cmd) +{ + int rc = -EINVAL; + + switch (anc_cmd) { + case ANC_CMD_ALGO_CALIBRATION: { if (this_anc_dev_info.state) - rc = anc_if_set_algo_module_id( + rc = anc_if_get_algo_module_cali_data( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - module_info_p->module_id); + info_p); else - this_anc_dev_info.algo_module_id = - module_info_p->module_id; + pr_err("%s: ANC is not running yet\n", + __func__); break; } + default: + pr_err("%s: ANC cmd wrong\n", + __func__); + break; } return rc; } - int msm_anc_dev_start(void) { int rc = 0; @@ -514,11 +528,6 @@ int msm_anc_dev_start(void) anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, this_anc_dev_info.algo_module_id); - if (this_anc_dev_info.bypass_mode != 0) - rc = anc_if_set_bypass_mode( - anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - this_anc_dev_info.bypass_mode); - group_id = get_group_id_from_port_id( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id); @@ -612,8 +621,6 @@ int msm_anc_dev_stop(void) this_anc_dev_info.state = 0; this_anc_dev_info.algo_module_id = 0; - this_anc_dev_info.rpm = 0; - this_anc_dev_info.bypass_mode = 0; pr_debug("%s: ANC devices stop successfully!\n", __func__); diff --git a/drivers/soc/qcom/qdsp6v2/audio_anc.c b/drivers/soc/qcom/qdsp6v2/audio_anc.c index 65c585886453..50cc255043df 100644 --- a/drivers/soc/qcom/qdsp6v2/audio_anc.c +++ b/drivers/soc/qcom/qdsp6v2/audio_anc.c @@ -44,17 +44,11 @@ static size_t get_user_anc_cmd_size(int32_t anc_cmd) case ANC_CMD_STOP: size = 0; break; - case ANC_CMD_RPM: - size = sizeof(struct audio_anc_rpm_info); - break; - case ANC_CMD_BYPASS_MODE: - size = sizeof(struct audio_anc_bypass_mode); - break; case ANC_CMD_ALGO_MODULE: size = sizeof(struct audio_anc_algo_module_info); break; case ANC_CMD_ALGO_CALIBRATION: - size = sizeof(struct audio_anc_algo_calibration_info); + size = sizeof(struct audio_anc_algo_calibration_header); break; default: pr_err("%s:Invalid anc cmd %d!", @@ -77,8 +71,6 @@ static int call_set_anc(int32_t anc_cmd, case ANC_CMD_STOP: ret = msm_anc_dev_stop(); break; - case ANC_CMD_RPM: - case ANC_CMD_BYPASS_MODE: case ANC_CMD_ALGO_MODULE: case ANC_CMD_ALGO_CALIBRATION: ret = msm_anc_dev_set_info(data, anc_cmd); @@ -98,7 +90,8 @@ static int call_get_anc(int32_t anc_cmd, int ret = 0; switch (anc_cmd) { - case ANC_CMD_RPM: + case ANC_CMD_ALGO_CALIBRATION: + ret = msm_anc_dev_get_info(data, anc_cmd); break; default: break; @@ -146,9 +139,9 @@ static long audio_anc_shared_ioctl(struct file *file, unsigned int cmd, pr_err("%s: Could not copy size value from user\n", __func__); ret = -EFAULT; goto done; - } else if (size < sizeof(struct audio_anc_packet)) { + } else if (size < sizeof(struct audio_anc_header)) { pr_err("%s: Invalid size sent to driver: %d, min size is %zd\n", - __func__, size, sizeof(struct audio_anc_packet)); + __func__, size, sizeof(struct audio_anc_header)); ret = -EINVAL; goto done; } diff --git a/drivers/soc/qcom/qdsp6v2/sdsp-anc.c b/drivers/soc/qcom/qdsp6v2/sdsp-anc.c index 9294485f7ff2..4e75bc89aa8f 100644 --- a/drivers/soc/qcom/qdsp6v2/sdsp-anc.c +++ b/drivers/soc/qcom/qdsp6v2/sdsp-anc.c @@ -38,7 +38,7 @@ struct anc_if_ctl { atomic_t status; wait_queue_head_t wait[AFE_MAX_PORTS]; struct task_struct *task; - struct anc_get_rpm_resp rpm_calib_data; + struct anc_get_algo_module_cali_data_resp cali_data_resp; uint32_t mmap_handle; struct mutex afe_cmd_lock; }; @@ -48,33 +48,23 @@ static struct anc_if_ctl this_anc_if; static int32_t anc_get_param_callback(uint32_t *payload, uint32_t payload_size) { - u32 param_id; - struct anc_get_rpm_resp *resp = - (struct anc_get_rpm_resp *) payload; - - if (!(&(resp->pdata))) { - pr_err("%s: Error: resp pdata is NULL\n", __func__); + if ((payload_size < (sizeof(uint32_t) + + sizeof(this_anc_if.cali_data_resp.pdata))) || + (payload_size > sizeof(this_anc_if.cali_data_resp))) { + pr_err("%s: Error: received size %d, calib_data size %zu\n", + __func__, payload_size, + sizeof(this_anc_if.cali_data_resp)); return -EINVAL; } - param_id = resp->pdata.param_id; - if (param_id == AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM) { - if (payload_size < sizeof(this_anc_if.rpm_calib_data)) { - pr_err("%s: Error: received size %d, calib_data size %zu\n", - __func__, payload_size, - sizeof(this_anc_if.rpm_calib_data)); - return -EINVAL; - } - - memcpy(&this_anc_if.rpm_calib_data, payload, - sizeof(this_anc_if.rpm_calib_data)); - if (!this_anc_if.rpm_calib_data.status) { - atomic_set(&this_anc_if.state, 0); - } else { - pr_debug("%s: calib resp status: %d", __func__, - this_anc_if.rpm_calib_data.status); - atomic_set(&this_anc_if.state, -1); - } + memcpy(&this_anc_if.cali_data_resp, payload, + payload_size); + if (!this_anc_if.cali_data_resp.status) { + atomic_set(&this_anc_if.state, 0); + } else { + pr_debug("%s: calib resp status: %d", __func__, + this_anc_if.cali_data_resp.status); + atomic_set(&this_anc_if.state, -1); } return 0; @@ -465,7 +455,7 @@ int anc_if_tdm_port_stop(u16 port_id) return anc_if_send_cmd_port_stop(port_id); } -int anc_if_set_rpm(u16 port_id, u32 rpm) +int anc_if_set_algo_module_id(u16 port_id, u32 module_id) { int ret = 0; int index; @@ -479,7 +469,7 @@ int anc_if_set_rpm(u16 port_id, u32 rpm) index = q6audio_get_port_index(port_id); { - struct anc_set_rpm_command config; + struct anc_set_algo_module_id_command config; memset(&config, 0, sizeof(config)); config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, @@ -496,16 +486,16 @@ int anc_if_set_rpm(u16 port_id, u32 rpm) config.param.payload_address_lsw = 0x00; config.param.payload_address_msw = 0x00; config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; - config.pdata.param_id = AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM; - config.pdata.param_size = sizeof(config.set_rpm); - config.set_rpm.minor_version = - AUD_MSVC_API_VERSION_DEV_ANC_ALGO_RPM; - config.set_rpm.rpm = rpm; + config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; + config.pdata.param_id = + AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID; + config.pdata.param_size = sizeof(config.set_algo_module_id); + config.set_algo_module_id.minor_version = 1; + config.set_algo_module_id.module_id = module_id; ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); if (ret) { - pr_err("%s: share resource for port 0x%x failed ret = %d\n", + pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", __func__, port_id, ret); } } @@ -513,10 +503,10 @@ int anc_if_set_rpm(u16 port_id, u32 rpm) return ret; } -int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) +int anc_if_set_anc_mic_spkr_layout(u16 port_id, +struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p) { int ret = 0; - int index; ret = anc_sdsp_interface_prepare(); @@ -528,7 +518,7 @@ int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) index = q6audio_get_port_index(port_id); { - struct anc_set_bypass_mode_command config; + struct anc_set_mic_spkr_layout_info_command config; memset(&config, 0, sizeof(config)); config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, @@ -545,17 +535,16 @@ int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) config.param.payload_address_lsw = 0x00; config.param.payload_address_msw = 0x00; config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; + config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; config.pdata.param_id = - AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_BYPASS_MODE; - config.pdata.param_size = sizeof(config.set_bypass_mode); - config.set_bypass_mode.minor_version = - AUD_MSVC_API_VERSION_DEV_ANC_ALGO_BYPASS_MODE; - config.set_bypass_mode.bypass_mode = bypass_mode; + AUD_MSVC_PARAM_ID_PORT_ANC_MIC_SPKR_LAYOUT_INFO; + config.pdata.param_size = sizeof(config.set_mic_spkr_layout); + memcpy(&config.set_mic_spkr_layout, set_mic_spkr_layout_p, + sizeof(config.set_mic_spkr_layout)); ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); if (ret) { - pr_err("%s: share resource for port 0x%x failed ret = %d\n", + pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", __func__, port_id, ret); } } @@ -563,10 +552,10 @@ int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) return ret; } -int anc_if_set_algo_module_id(u16 port_id, u32 module_id) + +int anc_if_set_algo_module_cali_data(u16 port_id, void *data_p) { int ret = 0; - int index; ret = anc_sdsp_interface_prepare(); @@ -578,45 +567,67 @@ int anc_if_set_algo_module_id(u16 port_id, u32 module_id) index = q6audio_get_port_index(port_id); { - struct anc_set_algo_module_id_command config; + struct anc_set_algo_module_cali_data_command *cali_data_cfg_p; + void *config_p = NULL; + int cmd_size = 0; + void *out_payload_p = NULL; + uint32_t *in_payload_p = (uint32_t *)data_p; + + uint32_t module_id = *in_payload_p; + uint32_t param_id = *(in_payload_p + 1); + uint32_t payload_size = *(in_payload_p + 2); + + cmd_size = sizeof(struct anc_set_algo_module_cali_data_command) + + payload_size; + config_p = kzalloc(cmd_size, GFP_KERNEL); + if (!config_p) { + ret = -ENOMEM; + return ret; + } - memset(&config, 0, sizeof(config)); - config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + memset(config_p, 0, cmd_size); + out_payload_p = config_p + + sizeof(struct anc_set_algo_module_cali_data_command); + + cali_data_cfg_p = + (struct anc_set_algo_module_cali_data_command *)config_p; + + cali_data_cfg_p->hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); - config.hdr.pkt_size = sizeof(config); - config.hdr.src_port = 0; - config.hdr.dest_port = 0; - config.hdr.token = index; - config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; - config.param.port_id = q6audio_get_port_id(port_id); - config.param.payload_size = sizeof(config) - + cali_data_cfg_p->hdr.pkt_size = cmd_size; + cali_data_cfg_p->hdr.src_port = 0; + cali_data_cfg_p->hdr.dest_port = 0; + cali_data_cfg_p->hdr.token = index; + cali_data_cfg_p->hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + cali_data_cfg_p->param.port_id = q6audio_get_port_id(port_id); + cali_data_cfg_p->param.payload_size = cmd_size - sizeof(struct apr_hdr) - - sizeof(config.param); - config.param.payload_address_lsw = 0x00; - config.param.payload_address_msw = 0x00; - config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; - config.pdata.param_id = - AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID; - config.pdata.param_size = sizeof(config.set_algo_module_id); - config.set_algo_module_id.minor_version = 1; - config.set_algo_module_id.module_id = module_id; + sizeof(struct aud_msvc_port_cmd_set_param_v2); + cali_data_cfg_p->param.payload_address_lsw = 0x00; + cali_data_cfg_p->param.payload_address_msw = 0x00; + cali_data_cfg_p->param.mem_map_handle = 0x00; + cali_data_cfg_p->pdata.module_id = module_id; + cali_data_cfg_p->pdata.param_id = param_id; + cali_data_cfg_p->pdata.param_size = payload_size; + + memcpy(out_payload_p, (in_payload_p + 3), payload_size); + + ret = anc_if_apr_send_pkt(cali_data_cfg_p, + &this_anc_if.wait[index]); + if (ret) + pr_err("%s: anc algo module calibration data for port 0x%x failed ret = %d\n", + __func__, port_id, ret); - ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); - if (ret) { - pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", - __func__, port_id, ret); - } + kfree(config_p); } return ret; } -int anc_if_set_anc_mic_spkr_layout(u16 port_id, -struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p) +int anc_if_get_algo_module_cali_data(u16 port_id, void *data_p) { int ret = 0; - int index; ret = anc_sdsp_interface_prepare(); @@ -628,35 +639,68 @@ struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p) index = q6audio_get_port_index(port_id); { - struct anc_set_mic_spkr_layout_info_command config; + struct anc_get_algo_module_cali_data_command *cali_data_cfg_p; + void *config_p = NULL; + int cmd_size = 0; + void *out_payload_p = NULL; + uint32_t *in_payload_p = (uint32_t *)data_p; + + uint32_t module_id = *in_payload_p; + uint32_t param_id = *(in_payload_p + 1); + uint32_t payload_size = *(in_payload_p + 2); + + cmd_size = sizeof(struct anc_get_algo_module_cali_data_command) + + payload_size; + config_p = kzalloc(cmd_size, GFP_KERNEL); + if (!config_p) { + ret = -ENOMEM; + return ret; + } - memset(&config, 0, sizeof(config)); - config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + memset(config_p, 0, cmd_size); + out_payload_p = config_p + + sizeof(struct anc_set_algo_module_cali_data_command); + + cali_data_cfg_p = + (struct anc_get_algo_module_cali_data_command *)config_p; + + cali_data_cfg_p->hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); - config.hdr.pkt_size = sizeof(config); - config.hdr.src_port = 0; - config.hdr.dest_port = 0; - config.hdr.token = index; - config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; - config.param.port_id = q6audio_get_port_id(port_id); - config.param.payload_size = sizeof(config) - + cali_data_cfg_p->hdr.pkt_size = cmd_size; + cali_data_cfg_p->hdr.src_port = 0; + cali_data_cfg_p->hdr.dest_port = 0; + cali_data_cfg_p->hdr.token = index; + cali_data_cfg_p->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2; + cali_data_cfg_p->param.port_id = q6audio_get_port_id(port_id); + cali_data_cfg_p->param.payload_size = cmd_size - sizeof(struct apr_hdr) - - sizeof(config.param); - config.param.payload_address_lsw = 0x00; - config.param.payload_address_msw = 0x00; - config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; - config.pdata.param_id = - AUD_MSVC_PARAM_ID_PORT_ANC_MIC_SPKR_LAYOUT_INFO; - config.pdata.param_size = sizeof(config.set_mic_spkr_layout); - - memcpy(&config.set_mic_spkr_layout, set_mic_spkr_layout_p, - sizeof(config.set_mic_spkr_layout)); - ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); - if (ret) { - pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", + sizeof(struct aud_msvc_port_cmd_get_param_v2); + cali_data_cfg_p->param.payload_address_lsw = 0x00; + cali_data_cfg_p->param.payload_address_msw = 0x00; + cali_data_cfg_p->param.mem_map_handle = 0x00; + cali_data_cfg_p->param.module_id = module_id; + cali_data_cfg_p->param.param_id = param_id; + cali_data_cfg_p->pdata.param_size = 0; + cali_data_cfg_p->pdata.module_id = 0; + cali_data_cfg_p->pdata.param_id = 0; + + ret = anc_if_apr_send_pkt(cali_data_cfg_p, + &this_anc_if.wait[index]); + if (ret) + pr_err("%s: anc algo module calibration data for port 0x%x failed ret = %d\n", __func__, port_id, ret); - } + + memcpy((in_payload_p + 3), + &this_anc_if.cali_data_resp.payload[0], payload_size); + + *in_payload_p = this_anc_if.cali_data_resp.pdata.module_id; + *(in_payload_p + 1) = + this_anc_if.cali_data_resp.pdata.param_id; + *(in_payload_p + 2) = + this_anc_if.cali_data_resp.pdata.param_size; + + kfree(config_p); } return ret; @@ -700,7 +744,6 @@ int anc_if_cmd_memory_map(int port_id, phys_addr_t dma_addr_p, mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL); if (!mmap_region_cmd) { ret = -ENOMEM; - pr_err("%s: allocate mmap_region_cmd failed\n", __func__); return ret; } diff --git a/drivers/soc/qcom/subsystem_notif_virt.c b/drivers/soc/qcom/subsystem_notif_virt.c index f8ce53cfa9f7..5c9acf7e4563 100644 --- a/drivers/soc/qcom/subsystem_notif_virt.c +++ b/drivers/soc/qcom/subsystem_notif_virt.c @@ -43,7 +43,7 @@ struct subsystem_descriptor { enum subsystem_type type; struct notifier_block nb; void *handle; - unsigned int ssr_irq; + int ssr_irq; struct list_head subsystem_list; struct work_struct work; }; @@ -91,7 +91,7 @@ static int subsys_notif_virt_probe(struct platform_device *pdev) struct device_node *child = NULL; const char *ss_type; struct resource *res; - struct subsystem_descriptor *subsystem; + struct subsystem_descriptor *subsystem = NULL; int ret = 0; if (!pdev) { @@ -193,7 +193,8 @@ static int subsys_notif_virt_probe(struct platform_device *pdev) } } - INIT_WORK(&subsystem->work, subsystem_notif_wq_func); + if (subsystem) + INIT_WORK(&subsystem->work, subsystem_notif_wq_func); return 0; err: destroy_workqueue(ssr_wq); diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index ee88a8aaf850..50cef91ad5a4 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -89,6 +89,9 @@ struct wdsp_glink_ch { /* Wait for ch connect state before sending any command */ wait_queue_head_t ch_connect_wait; + /* Wait for ch local and remote disconnect before channel free */ + wait_queue_head_t ch_free_wait; + /* * Glink channel configuration. This has to be the last * member of the strucuture as it has variable size @@ -338,7 +341,7 @@ static void wdsp_glink_notify_state(void *handle, const void *priv, mutex_lock(&ch->mutex); ch->channel_state = event; if (event == GLINK_CONNECTED) { - dev_dbg(wpriv->dev, "%s: glink channel: %s connected\n", + dev_info(wpriv->dev, "%s: glink channel: %s connected\n", __func__, ch->ch_cfg.name); for (i = 0; i < ch->ch_cfg.no_of_intents; i++) { @@ -360,31 +363,29 @@ static void wdsp_glink_notify_state(void *handle, const void *priv, ch->ch_cfg.name); wake_up(&ch->ch_connect_wait); - mutex_unlock(&ch->mutex); } else if (event == GLINK_LOCAL_DISCONNECTED) { /* * Don't use dev_dbg here as dev may not be valid if channel * closed from driver close. */ - pr_debug("%s: channel: %s disconnected locally\n", + pr_info("%s: channel: %s disconnected locally\n", __func__, ch->ch_cfg.name); mutex_unlock(&ch->mutex); - - if (ch->free_mem) { - kfree(ch); - ch = NULL; - } + ch->free_mem = true; + wake_up(&ch->ch_free_wait); + return; } else if (event == GLINK_REMOTE_DISCONNECTED) { - dev_dbg(wpriv->dev, "%s: remote channel: %s disconnected remotely\n", + pr_info("%s: remote channel: %s disconnected remotely\n", __func__, ch->ch_cfg.name); - mutex_unlock(&ch->mutex); /* * If remote disconnect happens, local side also has * to close the channel as per glink design in a * separate work_queue. */ - queue_work(wpriv->work_queue, &ch->lcl_ch_cls_wrk); + if (wpriv && wpriv->work_queue != NULL) + queue_work(wpriv->work_queue, &ch->lcl_ch_cls_wrk); } + mutex_unlock(&ch->mutex); } /* @@ -399,11 +400,11 @@ static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch) mutex_lock(&wpriv->glink_mutex); if (ch->handle) { ret = glink_close(ch->handle); + ch->handle = NULL; if (IS_ERR_VALUE(ret)) { dev_err(wpriv->dev, "%s: glink_close is failed, ret = %d\n", __func__, ret); } else { - ch->handle = NULL; dev_dbg(wpriv->dev, "%s: ch %s is closed\n", __func__, ch->ch_cfg.name); } @@ -451,6 +452,7 @@ static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch) ch->handle = NULL; ret = -EINVAL; } + ch->free_mem = false; } else { dev_err(wpriv->dev, "%s: ch %s is already opened\n", __func__, ch->ch_cfg.name); @@ -492,7 +494,7 @@ static int wdsp_glink_open_all_ch(struct wdsp_glink_priv *wpriv) err_open: for (j = 0; j < i; j++) - if (wpriv->ch[i]) + if (wpriv->ch[j]) wdsp_glink_close_ch(wpriv->ch[j]); done: @@ -631,6 +633,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, goto err_ch_mem; } ch[i]->channel_state = GLINK_LOCAL_DISCONNECTED; + ch[i]->free_mem = true; memcpy(&ch[i]->ch_cfg, payload, ch_cfg_size); payload += ch_cfg_size; @@ -654,6 +657,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, INIT_WORK(&ch[i]->lcl_ch_open_wrk, wdsp_glink_lcl_ch_open_wrk); INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk); init_waitqueue_head(&ch[i]->ch_connect_wait); + init_waitqueue_head(&ch[i]->ch_free_wait); } INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk); @@ -1060,36 +1064,48 @@ static int wdsp_glink_release(struct inode *inode, struct file *file) goto done; } + dev_info(wpriv->dev, "%s: closing wdsp_glink driver\n", __func__); if (wpriv->glink_state.handle) glink_unregister_link_state_cb(wpriv->glink_state.handle); flush_workqueue(wpriv->work_queue); - destroy_workqueue(wpriv->work_queue); - /* - * Clean up glink channel memory in channel state - * callback only if close channels are called from here. + * Wait for channel local and remote disconnect state notifications + * before freeing channel memory. */ - if (wpriv->ch) { - for (i = 0; i < wpriv->no_of_channels; i++) { - if (wpriv->ch[i]) { - wpriv->ch[i]->free_mem = true; - /* - * Channel handle NULL means channel is already - * closed. Free the channel memory here itself. - */ - if (!wpriv->ch[i]->handle) { - kfree(wpriv->ch[i]); - wpriv->ch[i] = NULL; - } else { - wdsp_glink_close_ch(wpriv->ch[i]); - } + for (i = 0; i < wpriv->no_of_channels; i++) { + if (wpriv->ch && wpriv->ch[i]) { + /* + * Only close glink channel from here if REMOTE has + * not already disconnected it + */ + wdsp_glink_close_ch(wpriv->ch[i]); + + ret = wait_event_timeout(wpriv->ch[i]->ch_free_wait, + (wpriv->ch[i]->free_mem == true), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: glink ch %s failed to notify states properly %d\n", + __func__, wpriv->ch[i]->ch_cfg.name, + wpriv->ch[i]->channel_state); + ret = -EINVAL; + goto done; } } + } - kfree(wpriv->ch); - wpriv->ch = NULL; + flush_workqueue(wpriv->work_queue); + destroy_workqueue(wpriv->work_queue); + wpriv->work_queue = NULL; + + for (i = 0; i < wpriv->no_of_channels; i++) { + if (wpriv->ch && wpriv->ch[i]) { + kfree(wpriv->ch[i]); + wpriv->ch[i] = NULL; + } } + kfree(wpriv->ch); + wpriv->ch = NULL; mutex_destroy(&wpriv->glink_mutex); mutex_destroy(&wpriv->rsp_mutex); diff --git a/drivers/soundwire/soundwire.c b/drivers/soundwire/soundwire.c index 63545651fe43..0e8cc399204e 100755..100644 --- a/drivers/soundwire/soundwire.c +++ b/drivers/soundwire/soundwire.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -241,7 +241,7 @@ int swr_remove_from_group(struct swr_device *dev, u8 dev_num) if (!dev->group_id) return 0; - if (master->gr_sid == dev_num) + if (master->gr_sid != dev_num) return 0; if (master->remove_from_group && master->remove_from_group(master)) diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c index 1dcaba2e79f6..a8458b9b6e3a 100644 --- a/drivers/soundwire/swr-wcd-ctrl.c +++ b/drivers/soundwire/swr-wcd-ctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1727,6 +1727,8 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) (swrm->state == SWR_MSTR_UP)) { dev_dbg(swrm->dev, "%s: SWR master is already UP: %d\n", __func__, swrm->state); + list_for_each_entry(swr_dev, &mstr->devices, dev_list) + swr_reset_device(swr_dev); } else { pm_runtime_mark_last_busy(&pdev->dev); mutex_unlock(&swrm->reslock); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 77903dbdd2d9..65e34250cab2 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1417,24 +1417,28 @@ static struct dma_buf_ops dma_buf_ops = { .kunmap = ion_dma_buf_kunmap, }; -struct dma_buf *ion_share_dma_buf(struct ion_client *client, - struct ion_handle *handle) +static struct dma_buf *__ion_share_dma_buf(struct ion_client *client, + struct ion_handle *handle, + bool lock_client) { DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct ion_buffer *buffer; struct dma_buf *dmabuf; bool valid_handle; - mutex_lock(&client->lock); + if (lock_client) + mutex_lock(&client->lock); valid_handle = ion_handle_validate(client, handle); if (!valid_handle) { WARN(1, "%s: invalid handle passed to share.\n", __func__); - mutex_unlock(&client->lock); + if (lock_client) + mutex_unlock(&client->lock); return ERR_PTR(-EINVAL); } buffer = handle->buffer; ion_buffer_get(buffer); - mutex_unlock(&client->lock); + if (lock_client) + mutex_unlock(&client->lock); exp_info.ops = &dma_buf_ops; exp_info.size = buffer->size; @@ -1449,14 +1453,21 @@ struct dma_buf *ion_share_dma_buf(struct ion_client *client, return dmabuf; } + +struct dma_buf *ion_share_dma_buf(struct ion_client *client, + struct ion_handle *handle) +{ + return __ion_share_dma_buf(client, handle, true); +} EXPORT_SYMBOL(ion_share_dma_buf); -int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle) +static int __ion_share_dma_buf_fd(struct ion_client *client, + struct ion_handle *handle, bool lock_client) { struct dma_buf *dmabuf; int fd; - dmabuf = ion_share_dma_buf(client, handle); + dmabuf = __ion_share_dma_buf(client, handle, lock_client); if (IS_ERR(dmabuf)) return PTR_ERR(dmabuf); @@ -1465,6 +1476,11 @@ int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle) dma_buf_put(dmabuf); return fd; } + +int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle) +{ + return __ion_share_dma_buf_fd(client, handle, true); +} EXPORT_SYMBOL(ion_share_dma_buf_fd); bool ion_dma_buf_is_secure(struct dma_buf *dmabuf) @@ -1489,6 +1505,12 @@ bool ion_dma_buf_is_secure(struct dma_buf *dmabuf) } EXPORT_SYMBOL(ion_dma_buf_is_secure); +static int ion_share_dma_buf_fd_nolock(struct ion_client *client, + struct ion_handle *handle) +{ + return __ion_share_dma_buf_fd(client, handle, false); +} + struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) { struct dma_buf *dmabuf; @@ -1640,11 +1662,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ion_handle *handle; - handle = ion_handle_get_by_id(client, data.handle.handle); - if (IS_ERR(handle)) + mutex_lock(&client->lock); + handle = ion_handle_get_by_id_nolock(client, data.handle.handle); + if (IS_ERR(handle)) { + mutex_unlock(&client->lock); return PTR_ERR(handle); - data.fd.fd = ion_share_dma_buf_fd(client, handle); - ion_handle_put(handle); + } + data.fd.fd = ion_share_dma_buf_fd_nolock(client, handle); + ion_handle_put_nolock(handle); + mutex_unlock(&client->lock); if (data.fd.fd < 0) ret = data.fd.fd; break; diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 77bc25dfd562..bd481af4035c 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -313,14 +313,37 @@ err: return ret; } +static void *ion_secure_cma_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + if (!is_buffer_hlos_assigned(buffer)) { + pr_info("%s: Mapping non-HLOS accessible buffer disallowed\n", + __func__); + return NULL; + } + return ion_cma_map_kernel(heap, buffer); +} + +static int ion_secure_cma_map_user(struct ion_heap *mapper, + struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + if (!is_buffer_hlos_assigned(buffer)) { + pr_info("%s: Mapping non-HLOS accessible buffer disallowed\n", + __func__); + return -EINVAL; + } + return ion_cma_mmap(mapper, buffer, vma); +} + static struct ion_heap_ops ion_secure_cma_ops = { .allocate = ion_secure_cma_allocate, .free = ion_secure_cma_free, .map_dma = ion_cma_heap_map_dma, .unmap_dma = ion_cma_heap_unmap_dma, .phys = ion_cma_phys, - .map_user = ion_cma_mmap, - .map_kernel = ion_cma_map_kernel, + .map_user = ion_secure_cma_map_user, + .map_kernel = ion_secure_cma_map_kernel, .unmap_kernel = ion_cma_unmap_kernel, .print_debug = ion_cma_print_debug, }; diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index a2ead280ac4e..403dadea5bb2 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -99,6 +99,11 @@ size_t ion_system_heap_secure_page_pool_total(struct ion_heap *heap, return total << PAGE_SHIFT; } +static int ion_heap_is_system_heap_type(enum ion_heap_type type) +{ + return type == ((enum ion_heap_type)ION_HEAP_TYPE_SYSTEM); +} + static struct page *alloc_buffer_page(struct ion_system_heap *heap, struct ion_buffer *buffer, unsigned long order, @@ -352,6 +357,13 @@ static int ion_system_heap_allocate(struct ion_heap *heap, int vmid = get_secure_vmid(buffer->flags); struct device *dev = heap->priv; + if (ion_heap_is_system_heap_type(buffer->heap->type) && + is_secure_vmid_valid(vmid)) { + pr_info("%s: System heap doesn't support secure allocations\n", + __func__); + return -EINVAL; + } + if (align > PAGE_SIZE) return -EINVAL; diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 803811597f37..c7585118a41c 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -170,14 +170,15 @@ out: sys_heap->ops->free(&buffer); } -static void process_one_shrink(struct ion_heap *sys_heap, +static void process_one_shrink(struct ion_system_secure_heap *secure_heap, + struct ion_heap *sys_heap, struct prefetch_info *info) { struct ion_buffer buffer; size_t pool_size, size; int ret; - buffer.heap = sys_heap; + buffer.heap = &secure_heap->heap; buffer.flags = info->vmid; pool_size = ion_system_heap_secure_page_pool_total(sys_heap, @@ -192,6 +193,7 @@ static void process_one_shrink(struct ion_heap *sys_heap, } buffer.private_flags = ION_PRIV_FLAG_SHRINKER_FREE; + buffer.heap = sys_heap; sys_heap->ops->free(&buffer); } @@ -211,7 +213,7 @@ static void ion_system_secure_heap_prefetch_work(struct work_struct *work) spin_unlock_irqrestore(&secure_heap->work_lock, flags); if (info->shrink) - process_one_shrink(sys_heap, info); + process_one_shrink(secure_heap, sys_heap, info); else process_one_prefetch(sys_heap, info); diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index 7326aa46a8f6..116a6fecaac5 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -678,6 +678,21 @@ int get_secure_vmid(unsigned long flags) return VMID_CP_SPSS_SP_SHARED; return -EINVAL; } + +bool is_buffer_hlos_assigned(struct ion_buffer *buffer) +{ + bool is_hlos = false; + + if (buffer->heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA && + (buffer->flags & ION_FLAG_CP_HLOS)) + is_hlos = true; + + if (get_secure_vmid(buffer->flags) <= 0) + is_hlos = true; + + return is_hlos; +} + /* fix up the cases where the ioctl direction bits are incorrect */ static unsigned int msm_ion_ioctl_dir(unsigned int cmd) { diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h index 098104d56fdb..f0f01f92c05c 100644 --- a/drivers/staging/android/ion/msm/msm_ion.h +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -175,6 +175,8 @@ int msm_ion_do_cache_offset_op( void *vaddr, unsigned int offset, unsigned long len, unsigned int cmd); +bool is_buffer_hlos_assigned(struct ion_buffer *buffer); + #else static inline struct ion_client *msm_ion_client_create(const char *name) { @@ -202,6 +204,11 @@ int msm_ion_do_cache_offset_op( return -ENODEV; } +static bool is_buffer_hlos_assigned(struct ion_buffer *buffer) +{ + return true; +} + #endif /* CONFIG_ION */ #endif diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 8f181caffca3..619c989c5f37 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -5275,11 +5275,11 @@ static int ni_E_init(struct comedi_device *dev, /* Digital I/O (PFI) subdevice */ s = &dev->subdevices[NI_PFI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->maxdata = 1; if (devpriv->is_m_series) { s->n_chan = 16; s->insn_bits = ni_pfi_insn_bits; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; ni_writew(dev, s->state, NI_M_PFI_DO_REG); for (i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i) { @@ -5288,6 +5288,7 @@ static int ni_E_init(struct comedi_device *dev, } } else { s->n_chan = 10; + s->subdev_flags = SDF_INTERNAL; } s->insn_config = ni_pfi_insn_config; diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c index 12a3893b98fd..ade29c4295b7 100644 --- a/drivers/staging/rts5208/rtsx_scsi.c +++ b/drivers/staging/rts5208/rtsx_scsi.c @@ -536,7 +536,7 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (sendbytes > 8) { memcpy(buf, inquiry_buf, 8); - memcpy(buf + 8, inquiry_string, sendbytes - 8); + strncpy(buf + 8, inquiry_string, sendbytes - 8); if (pro_formatter_flag) { /* Additional Length */ buf[4] = 0x33; diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c index 10fea7bb8f30..3db4a2570b19 100644 --- a/drivers/staging/rts5208/xd.c +++ b/drivers/staging/rts5208/xd.c @@ -1252,7 +1252,7 @@ static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk, reg = 0; rtsx_read_register(chip, XD_CTL, ®); if (reg & (XD_ECC1_ERROR | XD_ECC2_ERROR)) { - wait_timeout(100); + mdelay(100); if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 21f888ac550e..7199bac67333 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -306,6 +306,7 @@ void __transport_register_session( { const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; + unsigned long flags; se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; @@ -342,7 +343,7 @@ void __transport_register_session( se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]); } - spin_lock_irq(&se_nacl->nacl_sess_lock); + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); /* * The se_nacl->nacl_sess pointer will be set to the * last active I_T Nexus for each struct se_node_acl. @@ -351,7 +352,7 @@ void __transport_register_session( list_add_tail(&se_sess->sess_acl_list, &se_nacl->acl_sess_list); - spin_unlock_irq(&se_nacl->nacl_sess_lock); + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); } list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list); diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 802eac7e561b..2b8f2e0a4224 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -1915,7 +1915,7 @@ static __init int register_PCI(int i, struct pci_dev *dev) ByteIO_t UPCIRingInd = 0; if (!dev || !pci_match_id(rocket_pci_ids, dev) || - pci_enable_device(dev)) + pci_enable_device(dev) || i >= NUM_BOARDS) return 0; rcktpt_io_addr[i] = pci_resource_start(dev, 0); diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index bcc1fc027311..b9823eb9c195 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -833,8 +833,6 @@ int __uio_register_device(struct module *owner, if (ret) goto err_uio_dev_add_attributes; - info->uio_dev = idev; - if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { /* * Note that we deliberately don't use devm_request_irq @@ -850,6 +848,7 @@ int __uio_register_device(struct module *owner, goto err_request_irq; } + info->uio_dev = idev; return 0; err_request_irq: diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 61ea87917433..4380e4f600ab 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -453,7 +453,7 @@ static int clear_wdm_read_flag(struct wdm_device *desc) set_bit(WDM_RESPONDING, &desc->flags); spin_unlock_irq(&desc->iuspin); - rv = usb_submit_urb(desc->response, GFP_KERNEL); + rv = usb_submit_urb(desc->response, GFP_ATOMIC); spin_lock_irq(&desc->iuspin); if (rv) { dev_err(&desc->intf->dev, diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 40378487e023..a5e3e410db4e 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -529,8 +529,6 @@ static int resume_common(struct device *dev, int event) event == PM_EVENT_RESTORE); if (retval) { dev_err(dev, "PCI post-resume error %d!\n", retval); - if (hcd->shared_hcd) - usb_hc_died(hcd->shared_hcd); usb_hc_died(hcd); } } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7855b3e9a97f..530817c6783d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1283,6 +1283,11 @@ void usb_enable_interface(struct usb_device *dev, * is submitted that needs that bandwidth. Some other operating systems * allocate bandwidth early, when a configuration is chosen. * + * xHCI reserves bandwidth and configures the alternate setting in + * usb_hcd_alloc_bandwidth(). If it fails the original interface altsetting + * may be disabled. Drivers cannot rely on any particular alternate + * setting being in effect after a failure. + * * This call is synchronous, and may not be used in an interrupt context. * Also, drivers must not change altsettings while urbs are scheduled for * endpoints in that interface; all such urbs must first be completed @@ -1318,6 +1323,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) alternate); return -EINVAL; } + /* + * usb3 hosts configure the interface in usb_hcd_alloc_bandwidth, + * including freeing dropped endpoint ring buffers. + * Make sure the interface endpoints are flushed before that + */ + usb_disable_interface(dev, iface, false); /* Make sure we have enough bandwidth for this alternate interface. * Remove the current alt setting and add the new alt setting. diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 99f67764765f..37a5e07b3488 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -37,6 +37,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, + /* WORLDE Controller KS49 or Prodipe MIDI 49C USB controller */ + { USB_DEVICE(0x0218, 0x0201), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* WORLDE easy key (easykey.25) MIDI controller */ { USB_DEVICE(0x0218, 0x0401), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -259,6 +263,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* DJI CineSSD */ + { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 9f73ec68a23b..2e56d167ba05 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -543,6 +543,7 @@ struct dwc3_ep_events { * @dbg_ep_events: different events counter for endpoint * @dbg_ep_events_diff: differential events counter for endpoint * @dbg_ep_events_ts: timestamp for previous event counters + * @fifo_depth: allocated TXFIFO depth */ struct dwc3_ep { struct usb_ep endpoint; @@ -583,6 +584,7 @@ struct dwc3_ep { struct dwc3_ep_events dbg_ep_events; struct dwc3_ep_events dbg_ep_events_diff; struct timespec dbg_ep_events_ts; + int fifo_depth; }; enum dwc3_phy { @@ -813,7 +815,6 @@ struct dwc3_scratchpad_array { * @is_fpga: true when we are using the FPGA board * @needs_fifo_resize: not all users might want fifo resizing, flag it * @pullups_connected: true when Run/Stop bit is set - * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup @@ -853,6 +854,7 @@ struct dwc3_scratchpad_array { * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @create_reg_debugfs: create debugfs entry to allow dwc3 register dump + * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -988,7 +990,6 @@ struct dwc3 { unsigned is_fpga:1; unsigned needs_fifo_resize:1; unsigned pullups_connected:1; - unsigned resize_fifos:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; unsigned usb3_lpm_capable:1; @@ -1050,6 +1051,7 @@ struct dwc3 { wait_queue_head_t wait_linkstate; bool create_reg_debugfs; + int last_fifo_depth; }; /* -------------------------------------------------------------------------- */ @@ -1199,7 +1201,7 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode); -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); +int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep); /* check whether we are on the DWC_usb3 core */ static inline bool dwc3_is_usb3(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index dc06f4818e39..1e23738e20b3 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1132,7 +1132,8 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request) struct dwc3_gadget_ep_cmd_params params; const struct usb_endpoint_descriptor *desc = ep->desc; const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc; - u32 reg; + u32 reg; + int ret; memset(¶ms, 0x00, sizeof(params)); @@ -1181,6 +1182,10 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request) /* Set XferRsc Index for GSI EP */ if (!(dep->flags & DWC3_EP_ENABLED)) { + ret = dwc3_gadget_resize_tx_fifos(dwc, dep); + if (ret) + return; + memset(¶ms, 0x00, sizeof(params)); params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); dwc3_send_gadget_ep_cmd(dwc, dep->number, @@ -3969,7 +3974,10 @@ static void dwc3_otg_sm_work(struct work_struct *w) mdwc->otg_state = OTG_STATE_A_IDLE; goto ret; } - pm_wakeup_event(mdwc->dev, DWC3_WAKEUP_SRC_TIMEOUT); + if (mdwc->no_wakeup_src_in_hostmode) { + pm_wakeup_event(mdwc->dev, + DWC3_WAKEUP_SRC_TIMEOUT); + } } break; @@ -3987,7 +3995,10 @@ static void dwc3_otg_sm_work(struct work_struct *w) dbg_event(0xFF, "XHCIResume", 0); if (dwc) pm_runtime_resume(&dwc->xhci->dev); - pm_wakeup_event(mdwc->dev, DWC3_WAKEUP_SRC_TIMEOUT); + if (mdwc->no_wakeup_src_in_hostmode) { + pm_wakeup_event(mdwc->dev, + DWC3_WAKEUP_SRC_TIMEOUT); + } } break; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 24ecbc469eb6..1633807aee36 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -601,8 +601,9 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state; u32 cfg; - int ret; + int ret, num; u32 reg; + struct dwc3_ep *dep; cfg = le16_to_cpu(ctrl->wValue); @@ -611,6 +612,32 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return -EINVAL; case USB_STATE_ADDRESS: + /* + * If tx-fifo-resize flag is not set for the controller, then + * do not clear existing allocated TXFIFO since we do not + * allocate it again in dwc3_gadget_resize_tx_fifos + */ + if (dwc->needs_fifo_resize) { + /* Read ep0IN related TXFIFO size */ + dwc->last_fifo_depth = (dwc3_readl(dwc->regs, + DWC3_GTXFIFOSIZ(0)) & 0xFFFF); + /* Clear existing TXFIFO for all IN eps except ep0 */ + for (num = 0; num < dwc->num_in_eps; num++) { + dep = dwc->eps[(num << 1) | 1]; + if (num) { + dwc3_writel(dwc->regs, + DWC3_GTXFIFOSIZ(num), 0); + dep->fifo_depth = 0; + } else { + dep->fifo_depth = dwc->last_fifo_depth; + } + + dev_dbg(dwc->dev, "%s(): %s fifo_depth:%x\n", + __func__, dep->name, dep->fifo_depth); + dbg_event(0xFF, "fifo_reset", dep->number); + } + } + ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { @@ -635,9 +662,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); } - - dwc->resize_fifos = true; - dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET"); } break; @@ -1085,11 +1109,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { int ret; - if (dwc->resize_fifos) { - dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs"); - dwc3_gadget_resize_tx_fifos(dwc); - dwc->resize_fifos = 0; - } ret = dwc3_ep0_start_control_status(dep); if (WARN_ON_ONCE(ret)) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f6117ac0e301..48bfe2aaef1a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -172,88 +172,65 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) * * Unfortunately, due to many variables that's not always the case. */ -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) -{ - int last_fifo_depth = 0; - int ram1_depth; - int fifo_size; - int mdwidth; - int num; - int num_eps; - int max_packet = 1024; - struct usb_composite_dev *cdev = get_gadget_data(&dwc->gadget); - - if (!(cdev && cdev->config) || !dwc->needs_fifo_resize) +int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep) +{ + int fifo_size, mdwidth, max_packet = 1024; + int tmp, mult = 1; + + if (!dwc->needs_fifo_resize) return 0; - num_eps = dwc->num_in_eps; - ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); + /* resize IN endpoints excepts ep0 */ + if (!usb_endpoint_dir_in(dep->endpoint.desc) || + dep->endpoint.ep_num == 0) + return 0; + /* Don't resize already resized IN endpoint */ + if (dep->fifo_depth) { + dev_dbg(dwc->dev, "%s fifo_depth:%d is already set\n", + dep->endpoint.name, dep->fifo_depth); + return 0; + } + + mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); /* MDWIDTH is represented in bits, we need it in bytes */ mdwidth >>= 3; - last_fifo_depth = (dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)) & 0xFFFF); - dev_dbg(dwc->dev, "%s: num eps:%d max_packet:%d last_fifo_depth:%04x\n", - __func__, num_eps, max_packet, last_fifo_depth); - - /* Don't resize ep0IN TxFIFO, start with ep1IN only. */ - for (num = 1; num < num_eps; num++) { - /* bit0 indicates direction; 1 means IN ep */ - struct dwc3_ep *dep = dwc->eps[(num << 1) | 1]; - int mult = 1; - int tmp; - - tmp = max_packet + mdwidth; - /* - * Interfaces like MBIM or ECM is having multiple data - * interfaces. SET_CONFIG() happens before set_alt with - * data interface 1 which results into calling this API - * before GSI endpoint enabled. This results no txfifo - * resize with GSI endpoint causing low throughput. Hence - * use mult as 3 for GSI IN endpoint always irrespective - * USB speed. - */ - if (dep->endpoint.ep_type == EP_TYPE_GSI || - dep->endpoint.endless) - mult = 3; - - if (!(dep->flags & DWC3_EP_ENABLED)) { - dev_dbg(dwc->dev, "ep%dIn not enabled", num); - goto resize_fifo; - } - - if (((dep->endpoint.maxburst > 1) && - usb_endpoint_xfer_bulk(dep->endpoint.desc)) - || usb_endpoint_xfer_isoc(dep->endpoint.desc)) - mult = 3; - -resize_fifo: - tmp *= mult; - tmp += mdwidth; - - fifo_size = DIV_ROUND_UP(tmp, mdwidth); - - fifo_size |= (last_fifo_depth << 16); - - dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d", - dep->name, last_fifo_depth, fifo_size & 0xffff); - - last_fifo_depth += (fifo_size & 0xffff); - if (dwc->tx_fifo_size && - (last_fifo_depth >= dwc->tx_fifo_size)) { - /* - * Fifo size allocated exceeded available RAM size. - * Hence return error. - */ - dev_err(dwc->dev, "Fifosize(%d) > available RAM(%d)\n", - last_fifo_depth, dwc->tx_fifo_size); - return -ENOMEM; - } - - dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size); + if (dep->endpoint.ep_type == EP_TYPE_GSI || dep->endpoint.endless) + mult = 3; + + if (((dep->endpoint.maxburst > 1) && + usb_endpoint_xfer_bulk(dep->endpoint.desc)) + || usb_endpoint_xfer_isoc(dep->endpoint.desc)) + mult = 3; + + tmp = ((max_packet + mdwidth) * mult) + mdwidth; + fifo_size = DIV_ROUND_UP(tmp, mdwidth); + dep->fifo_depth = fifo_size; + fifo_size |= (dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)) & 0xffff0000) + + (dwc->last_fifo_depth << 16); + dwc->last_fifo_depth += (fifo_size & 0xffff); + + dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n", + dep->endpoint.name, dep->endpoint.ep_num, dwc->last_fifo_depth, + dep->fifo_depth); + + dbg_event(0xFF, "resize_fifo", dep->number); + dbg_event(0xFF, "fifo_depth", dep->fifo_depth); + /* Check fifo size allocation doesn't exceed available RAM size. */ + if (dwc->tx_fifo_size && + ((dwc->last_fifo_depth * mdwidth) >= dwc->tx_fifo_size)) { + dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n", + (dwc->last_fifo_depth * mdwidth), dwc->tx_fifo_size, + dep->endpoint.name, fifo_size); + dwc->last_fifo_depth -= (fifo_size & 0xffff); + dep->fifo_depth = 0; + WARN_ON(1); + return -ENOMEM; } + dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->endpoint.ep_num), + fifo_size); return 0; } @@ -622,6 +599,17 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name); if (!(dep->flags & DWC3_EP_ENABLED)) { + dep->endpoint.desc = desc; + dep->comp_desc = comp_desc; + dep->type = usb_endpoint_type(desc); + ret = dwc3_gadget_resize_tx_fifos(dwc, dep); + if (ret) { + dep->endpoint.desc = NULL; + dep->comp_desc = NULL; + dep->type = 0; + return ret; + } + ret = dwc3_gadget_start_config(dwc, dep); if (ret) { dev_err(dwc->dev, "start_config() failed for %s\n", @@ -641,9 +629,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, struct dwc3_trb *trb_st_hw; struct dwc3_trb *trb_link; - dep->endpoint.desc = desc; - dep->comp_desc = comp_desc; - dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); @@ -2894,9 +2879,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); - /* bus reset issued due to missing status stage of a control transfer */ - dwc->resize_fifos = 0; - /* Reset device address to zero */ reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_DEVADDR_MASK); diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index a47de8c31ce9..8efeadf30b4d 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1542,11 +1542,14 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) writel(tmp | BIT(USB_DETECT_ENABLE), &dev->usb->usbctl); } else { writel(tmp & ~BIT(USB_DETECT_ENABLE), &dev->usb->usbctl); - stop_activity(dev, dev->driver); + stop_activity(dev, NULL); } spin_unlock_irqrestore(&dev->lock, flags); + if (!is_on && dev->driver) + dev->driver->disconnect(&dev->gadget); + return 0; } @@ -2425,8 +2428,11 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver) nuke(&dev->ep[i]); /* report disconnect; the driver is already quiesced */ - if (driver) + if (driver) { + spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } usb_reinit(dev); } @@ -3272,6 +3278,8 @@ next_endpoints: BIT(PCI_RETRY_ABORT_INTERRUPT)) static void handle_stat1_irqs(struct net2280 *dev, u32 stat) +__releases(dev->lock) +__acquires(dev->lock) { struct net2280_ep *ep; u32 tmp, num, mask, scratch; @@ -3312,12 +3320,14 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) if (disconnect || reset) { stop_activity(dev, dev->driver); ep0_start(dev); + spin_unlock(&dev->lock); if (reset) usb_gadget_udc_reset (&dev->gadget, dev->driver); else (dev->driver->disconnect) (&dev->gadget); + spin_lock(&dev->lock); return; } } @@ -3336,6 +3346,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) tmp = BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT); if (stat & tmp) { writel(tmp, &dev->regs->irqstat1); + spin_unlock(&dev->lock); if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend(&dev->gadget); @@ -3346,6 +3357,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) dev->driver->resume(&dev->gadget); /* at high speed, note erratum 0133 */ } + spin_lock(&dev->lock); stat &= ~tmp; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 692ccc69345e..d5434e7a3b2e 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2565,7 +2565,7 @@ static int u132_get_frame(struct usb_hcd *hcd) } else { int frame = 0; dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - msleep(100); + mdelay(100); return frame; } } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 91af817278e3..abe6d3c17047 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3700,6 +3700,9 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->udev = NULL; spin_lock_irqsave(&xhci->lock, flags); + + virt_dev->udev = NULL; + /* Don't disable the slot if the host controller is dead. */ state = readl(&xhci->op_regs->status); if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4670e2f4c2de..278df845f066 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -279,13 +279,24 @@ config USB_QTI_KS_BRIDGE To compile this driver as a module, choose M here: the module will be called ks_bridge. If unsure, choose N. +config USB_QCOM_IPC_BRIDGE + tristate "USB QTI IPC bridge driver" + depends on USB + depends on USB_QCOM_DIAG_BRIDGE + help + Say Y here if you have a QTI modem device connected via USB that + will be bridged in kernel space. This driver works as a transport + layer for IPC router module that enables communication between + APPS processor and MODEM processor. + config USB_QCOM_DIAG_BRIDGE tristate "USB QTI diagnostic bridge driver" depends on USB + select USB_QCOM_IPC_BRIDGE help Say Y here if you have a QTI modem device connected via USB that will be bridged in kernel space. This driver communicates with the - diagnostic and QMI interfaces and allows for bridging with the diag - forwarding driver for diag interface and IPC router for QMI interface. + diagnostic interface and allows for bridging with the diag forwarding + driver. To compile this driver as a module, choose M here: the module will be called diag_bridge. If unsure, choose N. diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 442b6631162e..3d750671b85a 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -388,7 +388,7 @@ static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned ch mask &= 0x0f; val &= 0x0f; d = (priv->reg[1] & (~mask)) ^ val; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) + if (set_1284_register(pp, 2, d, GFP_ATOMIC)) return 0; priv->reg[1] = d; return d & 0xf; @@ -398,7 +398,7 @@ static unsigned char parport_uss720_read_status(struct parport *pp) { unsigned char ret; - if (get_1284_register(pp, 1, &ret, GFP_KERNEL)) + if (get_1284_register(pp, 1, &ret, GFP_ATOMIC)) return 0; return ret & 0xf8; } diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 512c84adcace..e8e8702d5adf 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -439,13 +439,13 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, { struct usb_yurex *dev; int i, set = 0, retval = 0; - char buffer[16]; + char buffer[16 + 1]; char *data = buffer; unsigned long long c, c2 = 0; signed long timeout = 0; DEFINE_WAIT(wait); - count = min(sizeof(buffer), count); + count = min(sizeof(buffer) - 1, count); dev = file->private_data; /* verify that we actually have some data to write */ @@ -464,6 +464,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, retval = -EFAULT; goto error; } + buffer[count] = 0; memset(dev->cntl_buffer, CMD_PADDING, YUREX_BUF_SIZE); switch (buffer[0]) { diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index 1bd67b24f916..bc9ff5ebd67c 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -178,7 +178,7 @@ struct ump_interrupt { } __attribute__((packed)); -#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 4) - 3) +#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 6) & 0x01) #define TIUMP_GET_FUNC_FROM_CODE(c) ((c) & 0x0f) #define TIUMP_INTERRUPT_CODE_LSR 0x03 #define TIUMP_INTERRUPT_CODE_MSR 0x04 diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index 98f35c656c02..0cd247f75b8b 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -227,7 +227,7 @@ struct ti_interrupt { } __attribute__((packed)); /* Interrupt codes */ -#define TI_GET_PORT_FROM_CODE(c) (((c) >> 4) - 3) +#define TI_GET_PORT_FROM_CODE(c) (((c) >> 6) & 0x01) #define TI_GET_FUNC_FROM_CODE(c) ((c) & 0x0f) #define TI_CODE_HARDWARE_ERROR 0xFF #define TI_CODE_DATA_ERROR 0x03 diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index dba51362d2e2..6c186b4df94a 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -341,6 +341,15 @@ static int queuecommand_lck(struct scsi_cmnd *srb, return 0; } + if ((us->fflags & US_FL_NO_ATA_1X) && + (srb->cmnd[0] == ATA_12 || srb->cmnd[0] == ATA_16)) { + memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB, + sizeof(usb_stor_sense_invalidCDB)); + srb->result = SAM_STAT_CHECK_CONDITION; + done(srb); + return 0; + } + /* enqueue the command and wake up the control thread */ srb->scsi_done = done; us->srb = srb; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1a34d2a89de6..898215cad351 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2213,6 +2213,13 @@ UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100, "Micro Mini 1GB", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), +/* Reported-by: Tim Anderson <tsa@biglakesoftware.com> */ +UNUSUAL_DEV( 0x2ca3, 0x0031, 0x0000, 0x9999, + "DJI", + "CineSSD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + /* * Nick Bowler <nbowler@elliptictech.com> * SCSI stack spams (otherwise harmless) error messages. diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 2510fa728d77..de119f11b78f 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -644,7 +644,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * * Valid mode specifiers for @mode_option: * - * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or + * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] or * <name>[-<bpp>][@<refresh>] * * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and @@ -653,10 +653,10 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * If 'M' is present after yres (and before refresh/bpp if present), * the function will compute the timings using VESA(tm) Coordinated * Video Timings (CVT). If 'R' is present after 'M', will compute with - * reduced blanking (for flatpanels). If 'i' is present, compute - * interlaced mode. If 'm' is present, add margins equal to 1.8% - * of xres rounded down to 8 pixels, and 1.8% of yres. The char - * 'i' and 'm' must be after 'M' and 'R'. Example: + * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute + * interlaced or progressive mode. If 'm' is present, add margins equal + * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars + * 'i', 'p' and 'm' must be after 'M' and 'R'. Example: * * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. * @@ -697,7 +697,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; + int yres_specified = 0, cvt = 0, rb = 0; + int interlace_specified = 0, interlace = 0; int margins = 0; u32 best, diff, tdiff; @@ -748,9 +749,17 @@ int fb_find_mode(struct fb_var_screeninfo *var, if (!cvt) margins = 1; break; + case 'p': + if (!cvt) { + interlace = 0; + interlace_specified = 1; + } + break; case 'i': - if (!cvt) + if (!cvt) { interlace = 1; + interlace_specified = 1; + } break; default: goto done; @@ -819,11 +828,21 @@ done: if ((name_matches(db[i], name, namelen) || (res_specified && res_matches(db[i], xres, yres))) && !fb_try_mode(var, info, &db[i], bpp)) { - if (refresh_specified && db[i].refresh == refresh) - return 1; + const int db_interlace = (db[i].vmode & + FB_VMODE_INTERLACED ? 1 : 0); + int score = abs(db[i].refresh - refresh); + + if (interlace_specified) + score += abs(db_interlace - interlace); + + if (!interlace_specified || + db_interlace == interlace) + if (refresh_specified && + db[i].refresh == refresh) + return 1; - if (abs(db[i].refresh - refresh) < diff) { - diff = abs(db[i].refresh - refresh); + if (score < diff) { + diff = score; best = i; } } diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c index 88adb2970b44..39662b2e3537 100644 --- a/drivers/video/fbdev/goldfishfb.c +++ b/drivers/video/fbdev/goldfishfb.c @@ -368,6 +368,7 @@ static int goldfish_fb_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base, fb->fb.fix.smem_start); iounmap(fb->reg_base); + kfree(fb); return 0; } diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index 230b02061b39..e9989fbdd2ba 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -433,6 +433,39 @@ static int mdss_debug_base_release(struct inode *inode, struct file *file) return 0; } +/** + * mdss_debug_base_is_valid_range - verify if requested memory range is valid + * @off: address offset in bytes + * @cnt: memory size in bytes + * Return: true if valid; false otherwise + */ +static bool mdss_debug_base_is_valid_range(u32 off, u32 cnt) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_debug_data *mdd = mdata->debug_inf.debug_data; + struct range_dump_node *node; + struct mdss_debug_base *base; + + pr_debug("check offset=0x%x cnt=0x%x\n", off, cnt); + + list_for_each_entry(base, &mdd->base_list, head) { + list_for_each_entry(node, &base->dump_list, head) { + pr_debug("%s: start=0x%x end=0x%x\n", node->range_name, + node->offset.start, node->offset.end); + + if (node->offset.start <= off + && off <= node->offset.end + && off + cnt <= node->offset.end) { + pr_debug("valid range requested\n"); + return true; + } + } + } + + pr_err("invalid range requested\n"); + return false; +} + static ssize_t mdss_debug_base_offset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -452,7 +485,8 @@ static ssize_t mdss_debug_base_offset_write(struct file *file, buf[count] = 0; /* end of string */ - sscanf(buf, "%5x %x", &off, &cnt); + if (sscanf(buf, "%5x %x", &off, &cnt) != 2) + return -EFAULT; if (off % sizeof(u32)) return -EINVAL; @@ -463,6 +497,9 @@ static ssize_t mdss_debug_base_offset_write(struct file *file, if (cnt > (dbg->max_offset - off)) cnt = dbg->max_offset - off; + if (!mdss_debug_base_is_valid_range(off, cnt)) + return -EINVAL; + mutex_lock(&mdss_debug_lock); dbg->off = off; dbg->cnt = cnt; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 5ba0480436a2..bf695ae0beaf 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -1803,17 +1803,13 @@ static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl) for (i = 0; i < ctrl->status_cmds.cmd_cnt; i++) len += lenp[i]; - for (i = 0; i < len; i++) { - pr_debug("[%i] return:0x%x status:0x%x\n", - i, (unsigned int)ctrl->return_buf[i], - (unsigned int)ctrl->status_value[j + i]); - MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], - ctrl->status_value[j + i]); - j += len; - } - for (j = 0; j < ctrl->groups; ++j) { for (i = 0; i < len; ++i) { + pr_debug("[%i] return:0x%x status:0x%x\n", + i, ctrl->return_buf[i], + (unsigned int)ctrl->status_value[group + i]); + MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], + ctrl->status_value[group + i]); if (ctrl->return_buf[i] != ctrl->status_value[group + i]) break; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index ec56bcf6e64e..710aebbd9c59 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -77,13 +77,15 @@ static inline u64 fudge_factor(u64 val, u32 numer, u32 denom) u64 result = val; if (val) { - u64 temp = -1UL; + u64 temp = U64_MAX; do_div(temp, val); if (temp > numer) { /* no overflow, so we can do the operation*/ result = (val * (u64)numer); do_div(result, denom); + } else { + pr_warn("Overflow, skip fudge factor\n"); } } return result; @@ -4892,7 +4894,8 @@ static inline void __mdss_mdp_mixer_write_layer(struct mdss_mdp_ctl *ctl, u32 off[NUM_MIXERCFG_REGS]; int i; - BUG_ON(!values || count < NUM_MIXERCFG_REGS); + if (WARN_ON(!values || count < NUM_MIXERCFG_REGS)) + return; __mdss_mdp_mixer_get_offsets(mixer_num, off, ARRAY_SIZE(off)); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index a259ddda2ce2..83ab9c3973af 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -738,8 +738,16 @@ int mdss_mdp_resource_control(struct mdss_mdp_ctl *ctl, u32 sw_event) int rc = 0; bool schedule_off = false; + if (!ctl) { + pr_err("%s invalid ctl\n", __func__); + rc = -EINVAL; + goto exit; + } + /* Get both controllers in the correct order for dual displays */ - mdss_mdp_get_split_display_ctls(&ctl, &sctl); + rc = mdss_mdp_get_split_display_ctls(&ctl, &sctl); + if (rc) + goto exit; ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx) { diff --git a/drivers/video/fbdev/msm/msm_dba/adv7533.c b/drivers/video/fbdev/msm/msm_dba/adv7533.c index a21b6db85ed8..7878276a06ef 100644 --- a/drivers/video/fbdev/msm/msm_dba/adv7533.c +++ b/drivers/video/fbdev/msm/msm_dba/adv7533.c @@ -1530,6 +1530,7 @@ static void adv7533_video_setup(struct adv7533 *pdata, { u32 h_total, hpw, hfp, hbp; u32 v_total, vpw, vfp, vbp; + int dsi_pixel_clock_divider = 0x00; if (!pdata || !cfg) { pr_err("%s: invalid input\n", __func__); @@ -1557,6 +1558,26 @@ static void adv7533_video_setup(struct adv7533 *pdata, v_total, cfg->v_active, cfg->v_front_porch, cfg->v_pulse_width, cfg->v_back_porch); + /* 0x16: dsi pclk divider control. + * bit2: 1 = manual dsi pclk divider control; 0 = automatic dsi + * pclk divider generation. + * bit3-7: the signal sets the dsi pclk divider setting when bit2 + * is enable. + * + * If bit2=0 means automatically select dsi pclk divider, so + * other bits(divider factor) has no impact. + * + * If bit2=1, the divider factor should be related to lane num below + * 4lanes : divide by 3; 3lanes : divide by 4; 2lanes : divide by 6 + * So the value of 0x16 can be set as follow: + * 4 lanes : 0x1C(00011 100) + * 3 lanes : 0x24(00100 100) + * 2 lanes : 0x34(00110 100) + * + * Here, use automatic dsi pclk divider generation, so set 0x00 + * to cec 0x16 register for all lanes numbers. + */ + adv7533_write(pdata, I2C_ADDR_CEC_DSI, 0x16, dsi_pixel_clock_divider); /* h_width */ adv7533_write(pdata, I2C_ADDR_CEC_DSI, 0x28, ((h_total & 0xFF0) >> 4)); diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 393ae1bc07e8..a8a6f072fb78 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -977,7 +977,7 @@ int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, { int r; - if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) + if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM) return -EINVAL; if (!notifier_inited) { diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index badee04ef496..71b5dca95bdb 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/compiler.h> #include <linux/module.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -1468,7 +1469,7 @@ static const struct file_operations viafb_vt1636_proc_fops = { #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ -static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) +static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v) { via_odev_to_seq(m, supported_odev_map[ viaparinfo->shared->chip_info.gfx_chip_name]); diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 502d3892d8a4..d71e7ad4d382 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -18,6 +18,7 @@ #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/list.h> +#include <linux/magic.h> /* This is the range of ioctl() numbers we claim as ours */ #define AUTOFS_IOC_FIRST AUTOFS_IOC_READY @@ -135,7 +136,8 @@ struct autofs_sb_info { static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) { - return (struct autofs_sb_info *)(sb->s_fs_info); + return sb->s_magic != AUTOFS_SUPER_MAGIC ? + NULL : (struct autofs_sb_info *)(sb->s_fs_info); } static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry) diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index a3ae0b2aeb5a..1132fe71b312 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -18,7 +18,6 @@ #include <linux/pagemap.h> #include <linux/parser.h> #include <linux/bitops.h> -#include <linux/magic.h> #include "autofs_i.h" #include <linux/module.h> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b9065d672887..ef90667e048b 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1711,7 +1711,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, const struct user_regset *regset = &view->regsets[i]; do_thread_regset_writeback(t->task, regset); if (regset->core_note_type && regset->get && - (!regset->active || regset->active(t->task, regset))) { + (!regset->active || regset->active(t->task, regset) > 0)) { int ret; size_t size = regset->n * regset->size; void *data = kmalloc(size, GFP_KERNEL); diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 1e668fb7dd4c..176a27bc63aa 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -574,6 +574,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, btrfs_rm_dev_replace_unblocked(fs_info); /* + * Increment dev_stats_ccnt so that btrfs_run_dev_stats() will + * update on-disk dev stats value during commit transaction + */ + atomic_inc(&tgt_device->dev_stats_ccnt); + + /* * this is again a consistent state where no dev_replace procedure * is running, the target device is part of the filesystem, the * source device is not part of the filesystem anymore and its 1st diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d106b981d86f..ae6e3a30e61e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1011,8 +1011,9 @@ static int btree_writepages(struct address_space *mapping, fs_info = BTRFS_I(mapping->host)->root->fs_info; /* this is a bit racy, but that's ok */ - ret = percpu_counter_compare(&fs_info->dirty_metadata_bytes, - BTRFS_DIRTY_METADATA_THRESH); + ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes, + BTRFS_DIRTY_METADATA_THRESH, + fs_info->dirty_metadata_batch); if (ret < 0) return 0; } @@ -3987,8 +3988,9 @@ static void __btrfs_btree_balance_dirty(struct btrfs_root *root, if (flush_delayed) btrfs_balance_delayed_items(root); - ret = percpu_counter_compare(&root->fs_info->dirty_metadata_bytes, - BTRFS_DIRTY_METADATA_THRESH); + ret = __percpu_counter_compare(&root->fs_info->dirty_metadata_bytes, + BTRFS_DIRTY_METADATA_THRESH, + root->fs_info->dirty_metadata_batch); if (ret > 0) { balance_dirty_pages_ratelimited( root->fs_info->btree_inode->i_mapping); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 493c7354ec0b..a72f941ca750 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10410,7 +10410,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) /* Don't want to race with allocators so take the groups_sem */ down_write(&space_info->groups_sem); spin_lock(&block_group->lock); - if (block_group->reserved || + if (block_group->reserved || block_group->pinned || btrfs_block_group_used(&block_group->item) || block_group->ro || list_is_singular(&block_group->list)) { diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 9ebe027cc4b7..cfe913d2d3df 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1318,18 +1318,19 @@ static void __del_reloc_root(struct btrfs_root *root) struct mapping_node *node = NULL; struct reloc_control *rc = root->fs_info->reloc_ctl; - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); - if (rb_node) { - node = rb_entry(rb_node, struct mapping_node, rb_node); - rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + if (rc) { + spin_lock(&rc->reloc_root_tree.lock); + rb_node = tree_search(&rc->reloc_root_tree.rb_root, + root->node->start); + if (rb_node) { + node = rb_entry(rb_node, struct mapping_node, rb_node); + rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + } + spin_unlock(&rc->reloc_root_tree.lock); + if (!node) + return; + BUG_ON((struct btrfs_root *)node->data != root); } - spin_unlock(&rc->reloc_root_tree.lock); - - if (!node) - return; - BUG_ON((struct btrfs_root *)node->data != root); spin_lock(&root->fs_info->trans_lock); list_del_init(&root->root_list); diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index bcbe42fb7e92..0e72a14228f8 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -285,6 +285,10 @@ static ssize_t cifs_stats_proc_write(struct file *file, atomic_set(&totBufAllocCount, 0); atomic_set(&totSmBufAllocCount, 0); #endif /* CONFIG_CIFS_STATS2 */ + spin_lock(&GlobalMid_Lock); + GlobalMaxActiveXid = 0; + GlobalCurrentXid = 0; + spin_unlock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock); list_for_each(tmp1, &cifs_tcp_ses_list) { server = list_entry(tmp1, struct TCP_Server_Info, @@ -297,6 +301,10 @@ static ssize_t cifs_stats_proc_write(struct file *file, struct cifs_tcon, tcon_list); atomic_set(&tcon->num_smbs_sent, 0); + spin_lock(&tcon->stat_lock); + tcon->bytes_read = 0; + tcon->bytes_written = 0; + spin_unlock(&tcon->stat_lock); if (server->ops->clear_stats) server->ops->clear_stats(tcon); } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0141aba9eca6..79a1bad88931 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3406,13 +3406,13 @@ readpages_get_pages(struct address_space *mapping, struct list_head *page_list, * should have access to this page, we're safe to simply set * PG_locked without checking it first. */ - __set_page_locked(page); + __SetPageLocked(page); rc = add_to_page_cache_locked(page, mapping, page->index, gfp); /* give up if we can't stick it in the cache */ if (rc) { - __clear_page_locked(page); + __ClearPageLocked(page); return rc; } @@ -3433,9 +3433,9 @@ readpages_get_pages(struct address_space *mapping, struct list_head *page_list, if (*bytes + PAGE_CACHE_SIZE > rsize) break; - __set_page_locked(page); + __SetPageLocked(page); if (add_to_page_cache_locked(page, mapping, page->index, gfp)) { - __clear_page_locked(page); + __ClearPageLocked(page); break; } list_move_tail(&page->lru, tmplist); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 97d1a15873c5..57b039ebfb1f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -373,8 +373,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + pfData->FileNameLength; - } else - new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); + } else { + u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset); + + if (old_entry + next_offset < old_entry) { + cifs_dbg(VFS, "invalid offset %u\n", next_offset); + return NULL; + } + new_entry = old_entry + next_offset; + } cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry); /* validate that new_entry is not past end of SMB */ if (new_entry >= end_of_smb) { diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 76ccf20fbfb7..0e62bf1ebbd7 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -185,6 +185,13 @@ smb2_check_message(char *buf, unsigned int length) return 0; /* + * Some windows servers (win2016) will pad also the final + * PDU in a compound to 8 bytes. + */ + if (((clc_len + 7) & ~7) == len) + return 0; + + /* * MacOS server pads after SMB2.1 write response with 3 bytes * of junk. Other servers match RFC1001 len to actual * SMB2/SMB3 frame length (header + smb2 response specific data) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 5f5ba807b414..f7111bb88ec1 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -315,7 +315,7 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon, smb2_hdr_assemble((struct smb2_hdr *) *request_buf, smb2_command, tcon); if (tcon != NULL) { -#ifdef CONFIG_CIFS_STATS2 +#ifdef CONFIG_CIFS_STATS uint16_t com_code = le16_to_cpu(smb2_command); cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]); #endif @@ -2402,33 +2402,38 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size) int len; unsigned int entrycount = 0; unsigned int next_offset = 0; - FILE_DIRECTORY_INFO *entryptr; + char *entryptr; + FILE_DIRECTORY_INFO *dir_info; if (bufstart == NULL) return 0; - entryptr = (FILE_DIRECTORY_INFO *)bufstart; + entryptr = bufstart; while (1) { - entryptr = (FILE_DIRECTORY_INFO *) - ((char *)entryptr + next_offset); - - if ((char *)entryptr + size > end_of_buf) { + if (entryptr + next_offset < entryptr || + entryptr + next_offset > end_of_buf || + entryptr + next_offset + size > end_of_buf) { cifs_dbg(VFS, "malformed search entry would overflow\n"); break; } - len = le32_to_cpu(entryptr->FileNameLength); - if ((char *)entryptr + len + size > end_of_buf) { + entryptr = entryptr + next_offset; + dir_info = (FILE_DIRECTORY_INFO *)entryptr; + + len = le32_to_cpu(dir_info->FileNameLength); + if (entryptr + len < entryptr || + entryptr + len > end_of_buf || + entryptr + len + size > end_of_buf) { cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n", end_of_buf); break; } - *lastentry = (char *)entryptr; + *lastentry = entryptr; entrycount++; - next_offset = le32_to_cpu(entryptr->NextEntryOffset); + next_offset = le32_to_cpu(dir_info->NextEntryOffset); if (!next_offset) break; } diff --git a/fs/dcache.c b/fs/dcache.c index 94f7541c154d..86f52a555dec 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -278,7 +278,8 @@ void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry spin_unlock(&dentry->d_lock); name->name = p->name; } else { - memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN); + memcpy(name->inline_name, dentry->d_iname, + dentry->d_name.len + 1); spin_unlock(&dentry->d_lock); name->name = name->inline_name; } diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index f18fc82fbe99..38c549d77a80 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -448,6 +448,8 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi, if (test_and_clear_bit(segno, free_i->free_segmap)) { free_i->free_segments++; + if (IS_CURSEC(sbi, secno)) + goto skip_free; next = find_next_bit(free_i->free_segmap, start_segno + sbi->segs_per_sec, start_segno); if (next >= start_segno + sbi->segs_per_sec) { @@ -455,6 +457,7 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi, free_i->free_sections++; } } +skip_free: spin_unlock(&free_i->segmap_lock); } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 08635dc2594f..b43aa473a0b6 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2286,12 +2286,17 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned int ovp_segments, reserved_segments; unsigned int main_segs, blocks_per_seg; + unsigned int sit_segs, nat_segs; + unsigned int sit_bitmap_size, nat_bitmap_size; + unsigned int log_blocks_per_seg; int i; total = le32_to_cpu(raw_super->segment_count); fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); - fsmeta += le32_to_cpu(raw_super->segment_count_sit); - fsmeta += le32_to_cpu(raw_super->segment_count_nat); + sit_segs = le32_to_cpu(raw_super->segment_count_sit); + fsmeta += sit_segs; + nat_segs = le32_to_cpu(raw_super->segment_count_nat); + fsmeta += nat_segs; fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); fsmeta += le32_to_cpu(raw_super->segment_count_ssa); @@ -2322,6 +2327,18 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) return 1; } + sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); + nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); + log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); + + if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 || + nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) { + f2fs_msg(sbi->sb, KERN_ERR, + "Wrong bitmap size: sit: %u, nat:%u", + sit_bitmap_size, nat_bitmap_size); + return 1; + } + if (unlikely(f2fs_cp_error(sbi))) { f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck"); return 1; diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 93fc62232ec2..9ae2c4d7e921 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -224,7 +224,8 @@ static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus) int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) { struct super_block *sb = inode->i_sb; - const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits; + struct msdos_sb_info *sbi = MSDOS_SB(sb); + const int limit = sb->s_maxbytes >> sbi->cluster_bits; struct fat_entry fatent; struct fat_cache_id cid; int nr; @@ -233,6 +234,12 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) *fclus = 0; *dclus = MSDOS_I(inode)->i_start; + if (!fat_valid_entry(sbi, *dclus)) { + fat_fs_error_ratelimit(sb, + "%s: invalid start cluster (i_pos %lld, start %08x)", + __func__, MSDOS_I(inode)->i_pos, *dclus); + return -EIO; + } if (cluster == 0) return 0; @@ -249,9 +256,8 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) /* prevent the infinite loop of cluster chain */ if (*fclus > limit) { fat_fs_error_ratelimit(sb, - "%s: detected the cluster chain loop" - " (i_pos %lld)", __func__, - MSDOS_I(inode)->i_pos); + "%s: detected the cluster chain loop (i_pos %lld)", + __func__, MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } @@ -261,9 +267,8 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) goto out; else if (nr == FAT_ENT_FREE) { fat_fs_error_ratelimit(sb, - "%s: invalid cluster chain (i_pos %lld)", - __func__, - MSDOS_I(inode)->i_pos); + "%s: invalid cluster chain (i_pos %lld)", + __func__, MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } else if (nr == FAT_ENT_EOF) { diff --git a/fs/fat/fat.h b/fs/fat/fat.h index be5e15323bab..1849b1adb6b9 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -344,6 +344,11 @@ static inline void fatent_brelse(struct fat_entry *fatent) fatent->fat_inode = NULL; } +static inline bool fat_valid_entry(struct msdos_sb_info *sbi, int entry) +{ + return FAT_START_ENT <= entry && entry < sbi->max_cluster; +} + extern void fat_ent_access_init(struct super_block *sb); extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 6abd78629140..e1f7655e75cb 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -23,7 +23,7 @@ static void fat12_ent_blocknr(struct super_block *sb, int entry, { struct msdos_sb_info *sbi = MSDOS_SB(sb); int bytes = entry + (entry >> 1); - WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); + WARN_ON(!fat_valid_entry(sbi, entry)); *offset = bytes & (sb->s_blocksize - 1); *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); } @@ -33,7 +33,7 @@ static void fat_ent_blocknr(struct super_block *sb, int entry, { struct msdos_sb_info *sbi = MSDOS_SB(sb); int bytes = (entry << sbi->fatent_shift); - WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); + WARN_ON(!fat_valid_entry(sbi, entry)); *offset = bytes & (sb->s_blocksize - 1); *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); } @@ -354,7 +354,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) int err, offset; sector_t blocknr; - if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { + if (!fat_valid_entry(sbi, entry)) { fatent_brelse(fatent); fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); return -EIO; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 61296ecbd0e2..09476bb8f6cd 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1476,7 +1476,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift; lblock = offset >> shift; lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; - if (lblock_stop > end_of_file) + if (lblock_stop > end_of_file && ip != GFS2_I(sdp->sd_rindex)) return 1; size = (lblock_stop - lblock) << shift; diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 6fc766df0461..2a6f3c67cb3f 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -74,9 +74,10 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) if (!fd->bnode) { if (!tree->root) hfs_btree_inc_height(tree); - fd->bnode = hfs_bnode_find(tree, tree->leaf_head); - if (IS_ERR(fd->bnode)) - return PTR_ERR(fd->bnode); + node = hfs_bnode_find(tree, tree->leaf_head); + if (IS_ERR(node)) + return PTR_ERR(node); + fd->bnode = node; fd->record = -1; } new_node = NULL; diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index d0f39dcbb58e..2b6e2ad57bf9 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -77,13 +77,13 @@ again: cpu_to_be32(HFSP_HARDLINK_TYPE) && entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && + HFSPLUS_SB(sb)->hidden_dir && (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)-> create_date || entry.file.create_date == HFSPLUS_I(d_inode(sb->s_root))-> - create_date) && - HFSPLUS_SB(sb)->hidden_dir) { + create_date)) { struct qstr str; char name[32]; diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index fa40e756c501..422e00dc5f3b 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -521,8 +521,10 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) goto out_put_root; if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { hfs_find_exit(&fd); - if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) + if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) { + err = -EINVAL; goto out_put_root; + } inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id)); if (IS_ERR(inode)) { err = PTR_ERR(inode); diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index e2e857affbf2..0647cb1ede56 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -911,16 +911,21 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r if (hdr_arg.minorversion == 0) { cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident); - if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) + if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) { + if (cps.clp) + nfs_put_client(cps.clp); goto out_invalidcred; + } } cps.minorversion = hdr_arg.minorversion; hdr_res.taglen = hdr_arg.taglen; hdr_res.tag = hdr_arg.tag; - if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) + if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) { + if (cps.clp) + nfs_put_client(cps.clp); return rpc_system_err; - + } while (status == 0 && nops != hdr_arg.nops) { status = process_op(nops, rqstp, &xdr_in, argp, &xdr_out, resp, &cps); diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 63a0d0ba36de..64c5386d0c1b 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, struct dentry *upperdir; struct dentry *upperdentry; const struct cred *old_cred; - struct cred *override_cred; char *link = NULL; if (WARN_ON(!workdir)) @@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, return PTR_ERR(link); } - err = -ENOMEM; - override_cred = prepare_creds(); - if (!override_cred) - goto out_free_link; - - override_cred->fsuid = stat->uid; - override_cred->fsgid = stat->gid; - /* - * CAP_SYS_ADMIN for copying up extended attributes - * CAP_DAC_OVERRIDE for create - * CAP_FOWNER for chmod, timestamp update - * CAP_FSETID for chmod - * CAP_CHOWN for chown - * CAP_MKNOD for mknod - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_FOWNER); - cap_raise(override_cred->cap_effective, CAP_FSETID); - cap_raise(override_cred->cap_effective, CAP_CHOWN); - cap_raise(override_cred->cap_effective, CAP_MKNOD); - old_cred = override_creds(override_cred); + old_cred = ovl_override_creds(dentry->d_sb); err = -EIO; if (lock_rename(workdir, upperdir) != NULL) { @@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, out_unlock: unlock_rename(workdir, upperdir); revert_creds(old_cred); - put_cred(override_cred); -out_free_link: if (link) free_page((unsigned long) link); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 327177df03a5..f8aa54272121 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -408,28 +408,13 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, err = ovl_create_upper(dentry, inode, &stat, link, hardlink); } else { const struct cred *old_cred; - struct cred *override_cred; - err = -ENOMEM; - override_cred = prepare_creds(); - if (!override_cred) - goto out_iput; - - /* - * CAP_SYS_ADMIN for setting opaque xattr - * CAP_DAC_OVERRIDE for create in workdir, rename - * CAP_FOWNER for removing whiteout from sticky dir - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_FOWNER); - old_cred = override_creds(override_cred); + old_cred = ovl_override_creds(dentry->d_sb); err = ovl_create_over_whiteout(dentry, inode, &stat, link, hardlink); revert_creds(old_cred); - put_cred(override_cred); } if (!err) @@ -659,32 +644,11 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir) if (OVL_TYPE_PURE_UPPER(type)) { err = ovl_remove_upper(dentry, is_dir); } else { - const struct cred *old_cred; - struct cred *override_cred; - - err = -ENOMEM; - override_cred = prepare_creds(); - if (!override_cred) - goto out_drop_write; - - /* - * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir - * CAP_DAC_OVERRIDE for create in workdir, rename - * CAP_FOWNER for removing whiteout from sticky dir - * CAP_FSETID for chmod of opaque dir - * CAP_CHOWN for chown of opaque dir - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_FOWNER); - cap_raise(override_cred->cap_effective, CAP_FSETID); - cap_raise(override_cred->cap_effective, CAP_CHOWN); - old_cred = override_creds(override_cred); + const struct cred *old_cred = ovl_override_creds(dentry->d_sb); err = ovl_remove_and_whiteout(dentry, is_dir); revert_creds(old_cred); - put_cred(override_cred); } out_drop_write: ovl_drop_write(dentry); @@ -723,7 +687,6 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old, bool new_is_dir = false; struct dentry *opaquedir = NULL; const struct cred *old_cred = NULL; - struct cred *override_cred = NULL; err = -EINVAL; if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE)) @@ -792,26 +755,8 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old, old_opaque = !OVL_TYPE_PURE_UPPER(old_type); new_opaque = !OVL_TYPE_PURE_UPPER(new_type); - if (old_opaque || new_opaque) { - err = -ENOMEM; - override_cred = prepare_creds(); - if (!override_cred) - goto out_drop_write; - - /* - * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir - * CAP_DAC_OVERRIDE for create in workdir - * CAP_FOWNER for removing whiteout from sticky dir - * CAP_FSETID for chmod of opaque dir - * CAP_CHOWN for chown of opaque dir - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_FOWNER); - cap_raise(override_cred->cap_effective, CAP_FSETID); - cap_raise(override_cred->cap_effective, CAP_CHOWN); - old_cred = override_creds(override_cred); - } + if (old_opaque || new_opaque) + old_cred = ovl_override_creds(old->d_sb); if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) { opaquedir = ovl_check_empty_and_clear(new); @@ -942,10 +887,8 @@ out_dput_old: out_unlock: unlock_rename(new_upperdir, old_upperdir); out_revert_creds: - if (old_opaque || new_opaque) { + if (old_opaque || new_opaque) revert_creds(old_cred); - put_cred(override_cred); - } out_drop_write: ovl_drop_write(old); out: diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 28316b292b8a..27a42975d7cd 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentry); bool ovl_dentry_is_opaque(struct dentry *dentry); void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque); bool ovl_is_whiteout(struct dentry *dentry); +const struct cred *ovl_override_creds(struct super_block *sb); void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); @@ -164,6 +165,8 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list); void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list); void ovl_cache_free(struct list_head *list); int ovl_check_d_type_supported(struct path *realpath); +void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, + struct dentry *dentry, int level); /* inode.c */ int ovl_setattr(struct dentry *dentry, struct iattr *attr); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 0c59955c4653..da999e73c97a 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -36,7 +36,8 @@ struct ovl_dir_cache { struct ovl_readdir_data { struct dir_context ctx; - bool is_merge; + struct dentry *dentry; + bool is_lowest; struct rb_root root; struct list_head *list; struct list_head middle; @@ -140,9 +141,9 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, return 0; } -static int ovl_fill_lower(struct ovl_readdir_data *rdd, - const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static int ovl_fill_lowest(struct ovl_readdir_data *rdd, + const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) { struct ovl_cache_entry *p; @@ -194,10 +195,10 @@ static int ovl_fill_merge(struct dir_context *ctx, const char *name, container_of(ctx, struct ovl_readdir_data, ctx); rdd->count++; - if (!rdd->is_merge) + if (!rdd->is_lowest) return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); else - return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); + return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type); } static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) @@ -206,17 +207,8 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) struct ovl_cache_entry *p; struct dentry *dentry; const struct cred *old_cred; - struct cred *override_cred; - - override_cred = prepare_creds(); - if (!override_cred) - return -ENOMEM; - /* - * CAP_DAC_OVERRIDE for lookup - */ - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - old_cred = override_creds(override_cred); + old_cred = ovl_override_creds(rdd->dentry->d_sb); err = mutex_lock_killable(&dir->d_inode->i_mutex); if (!err) { @@ -232,7 +224,6 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) mutex_unlock(&dir->d_inode->i_mutex); } revert_creds(old_cred); - put_cred(override_cred); return err; } @@ -257,7 +248,7 @@ static inline int ovl_dir_read(struct path *realpath, err = rdd->err; } while (!err && rdd->count); - if (!err && rdd->first_maybe_whiteout) + if (!err && rdd->first_maybe_whiteout && rdd->dentry) err = ovl_check_whiteouts(realpath->dentry, rdd); fput(realfile); @@ -288,9 +279,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) struct path realpath; struct ovl_readdir_data rdd = { .ctx.actor = ovl_fill_merge, + .dentry = dentry, .list = list, .root = RB_ROOT, - .is_merge = false, + .is_lowest = false, }; int idx, next; @@ -307,7 +299,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) * allows offsets to be reasonably constant */ list_add(&rdd.middle, rdd.list); - rdd.is_merge = true; + rdd.is_lowest = true; err = ovl_dir_read(&realpath, &rdd); list_del(&rdd.middle); } @@ -618,3 +610,64 @@ int ovl_check_d_type_supported(struct path *realpath) return rdd.d_type_supported; } + +static void ovl_workdir_cleanup_recurse(struct path *path, int level) +{ + int err; + struct inode *dir = path->dentry->d_inode; + LIST_HEAD(list); + struct ovl_cache_entry *p; + struct ovl_readdir_data rdd = { + .ctx.actor = ovl_fill_merge, + .dentry = NULL, + .list = &list, + .root = RB_ROOT, + .is_lowest = false, + }; + + err = ovl_dir_read(path, &rdd); + if (err) + goto out; + + inode_lock_nested(dir, I_MUTEX_PARENT); + list_for_each_entry(p, &list, l_node) { + struct dentry *dentry; + + if (p->name[0] == '.') { + if (p->len == 1) + continue; + if (p->len == 2 && p->name[1] == '.') + continue; + } + dentry = lookup_one_len(p->name, path->dentry, p->len); + if (IS_ERR(dentry)) + continue; + if (dentry->d_inode) + ovl_workdir_cleanup(dir, path->mnt, dentry, level); + dput(dentry); + } + inode_unlock(dir); +out: + ovl_cache_free(&list); +} + +void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, + struct dentry *dentry, int level) +{ + int err; + + if (!d_is_dir(dentry) || level > 1) { + ovl_cleanup(dir, dentry); + return; + } + + err = ovl_do_rmdir(dir, dentry); + if (err) { + struct path path = { .mnt = mnt, .dentry = dentry }; + + inode_unlock(dir); + ovl_workdir_cleanup_recurse(&path, level + 1); + inode_lock_nested(dir, I_MUTEX_PARENT); + ovl_cleanup(dir, dentry); + } +} diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 0035cb80ecd1..fa20c95bd456 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -42,6 +42,8 @@ struct ovl_fs { long lower_namelen; /* pathnames of lower and upper dirs, for show_options */ struct ovl_config config; + /* creds of process who forced instantiation of super block */ + const struct cred *creator_cred; }; struct ovl_dir_cache; @@ -246,6 +248,13 @@ bool ovl_is_whiteout(struct dentry *dentry) return inode && IS_WHITEOUT(inode); } +const struct cred *ovl_override_creds(struct super_block *sb) +{ + struct ovl_fs *ofs = sb->s_fs_info; + + return override_creds(ofs->creator_cred); +} + static bool ovl_is_opaquedir(struct dentry *dentry) { int res; @@ -587,6 +596,7 @@ static void ovl_put_super(struct super_block *sb) kfree(ufs->config.lowerdir); kfree(ufs->config.upperdir); kfree(ufs->config.workdir); + put_cred(ufs->creator_cred); kfree(ufs); } @@ -774,7 +784,7 @@ retry: goto out_dput; retried = true; - ovl_cleanup(dir, work); + ovl_workdir_cleanup(dir, mnt, work, 0); dput(work); goto retry; } @@ -1107,10 +1117,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) else sb->s_d_op = &ovl_dentry_operations; + ufs->creator_cred = prepare_creds(); + if (!ufs->creator_cred) + goto out_put_lower_mnt; + err = -ENOMEM; oe = ovl_alloc_entry(numlower); if (!oe) - goto out_put_lower_mnt; + goto out_put_cred; root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe)); if (!root_dentry) @@ -1143,6 +1157,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) out_free_oe: kfree(oe); +out_put_cred: + put_cred(ufs->creator_cred); out_put_lower_mnt: for (i = 0; i < ufs->numlower; i++) mntput(ufs->lower_mnt[i]); diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index e11672aa4575..ecdb3baa1283 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -421,7 +421,12 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size, vaddr = vmap(pages, page_count, VM_MAP, prot); kfree(pages); - return vaddr; + /* + * Since vmap() uses page granularity, we must add the offset + * into the page here, to get the byte granularity address + * into the mapping to represent the actual "start" location. + */ + return vaddr + offset_in_page(start); } static void *persistent_ram_iomap(phys_addr_t start, size_t size, @@ -440,6 +445,11 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, else va = ioremap_wc(start, size); + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the + * vmap() case in persistent_ram_vmap() above. + */ return va; } @@ -460,7 +470,7 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, return -ENOMEM; } - prz->buffer = prz->vaddr + offset_in_page(start); + prz->buffer = prz->vaddr; prz->buffer_size = size - sizeof(struct persistent_ram_buffer); return 0; @@ -507,7 +517,8 @@ void persistent_ram_free(struct persistent_ram_zone *prz) if (prz->vaddr) { if (pfn_valid(prz->paddr >> PAGE_SHIFT)) { - vunmap(prz->vaddr); + /* We must vunmap() at page-granularity. */ + vunmap(prz->vaddr - offset_in_page(prz->paddr)); } else { iounmap(prz->vaddr); release_mem_region(prz->paddr, prz->size); diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index 6ca00471afbf..d920a646b578 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -270,7 +270,7 @@ struct reiserfs_journal_list { struct mutex j_commit_mutex; unsigned int j_trans_id; - time_t j_timestamp; + time64_t j_timestamp; /* write-only but useful for crash dump analysis */ struct reiserfs_list_bitmap *j_list_bitmap; struct buffer_head *j_commit_bh; /* commit buffer head */ struct reiserfs_journal_cnode *j_realblock; diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 27ec726e7a46..1ad7718c05d9 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -264,7 +264,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, pr_info("sdcardfs: dev_name -> %s\n", dev_name); pr_info("sdcardfs: options -> %s\n", (char *)raw_data); - pr_info("sdcardfs: mnt -> %p\n", mnt); + pr_info("sdcardfs: mnt -> %pK\n", mnt); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index cffcdb11cb8a..fa7d9d2c5c2b 100644 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -144,7 +144,7 @@ static int sdcardfs_remount_fs2(struct vfsmount *mnt, struct super_block *sb, pr_err("sdcardfs: remount flags 0x%x unsupported\n", *flags); err = -EINVAL; } - pr_info("Remount options were %s for vfsmnt %p.\n", options, mnt); + pr_info("Remount options were %s for vfsmnt %pK.\n", options, mnt); err = parse_options_remount(sb, options, *flags & ~MS_SILENT, mnt->data); diff --git a/include/linux/bug.h b/include/linux/bug.h index 91eedf5fae38..218ac5875124 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -115,4 +115,23 @@ static inline enum bug_trap_type report_bug(unsigned long bug_addr, #else #define PANIC_CORRUPTION 0 #endif /* CONFIG_PANIC_ON_DATA_CORRUPTION */ + +/* + * Since detected data corruption should stop operation on the affected + * structures. Return value must be checked and sanely acted on by caller. + */ +static inline __must_check bool check_data_corruption(bool v) { return v; } +#define CHECK_DATA_CORRUPTION(condition, fmt, ...) \ + check_data_corruption(({ \ + bool corruption = unlikely(condition); \ + if (corruption) { \ + if (IS_ENABLED(CONFIG_BUG_ON_DATA_CORRUPTION)) { \ + pr_err(fmt, ##__VA_ARGS__); \ + BUG(); \ + } else \ + WARN(1, fmt, ##__VA_ARGS__); \ + } \ + corruption; \ + })) + #endif /* _LINUX_BUG_H */ diff --git a/include/linux/list.h b/include/linux/list.h index 993395a2e55c..d5750f2f1c36 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -28,27 +28,42 @@ static inline void INIT_LIST_HEAD(struct list_head *list) list->prev = list; } +#ifdef CONFIG_DEBUG_LIST +extern bool __list_add_valid(struct list_head *new, + struct list_head *prev, + struct list_head *next); +extern bool __list_del_entry_valid(struct list_head *entry); +#else +static inline bool __list_add_valid(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + return true; +} +static inline bool __list_del_entry_valid(struct list_head *entry) +{ + return true; +} +#endif + /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ -#ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { + if (!__list_add_valid(new, prev, next)) + return; + next->prev = new; new->next = next; new->prev = prev; prev->next = new; } -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif /** * list_add - add a new entry @@ -96,22 +111,20 @@ static inline void __list_del(struct list_head * prev, struct list_head * next) * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ -#ifndef CONFIG_DEBUG_LIST static inline void __list_del_entry(struct list_head *entry) { + if (!__list_del_entry_valid(entry)) + return; + __list_del(entry->prev, entry->next); } static inline void list_del(struct list_head *entry) { - __list_del(entry->prev, entry->next); + __list_del_entry(entry); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } -#else -extern void __list_del_entry(struct list_head *entry); -extern void list_del(struct list_head *entry); -#endif /** * list_replace - replace old entry by new one diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index fe0a5de1eda5..29c17fae9bbf 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -404,7 +404,7 @@ struct kioctx_table; struct mm_struct { struct vm_area_struct *mmap; /* list of VMAs */ struct rb_root mm_rb; - u32 vmacache_seqnum; /* per-thread vmacache */ + u64 vmacache_seqnum; /* per-thread vmacache */ #ifdef CONFIG_MMU unsigned long (*get_unmapped_area) (struct file *filp, unsigned long addr, unsigned long len, diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h index 772362adf471..053824b0a412 100644 --- a/include/linux/mmdebug.h +++ b/include/linux/mmdebug.h @@ -56,4 +56,10 @@ void dump_mm(const struct mm_struct *mm); #define VIRTUAL_BUG_ON(cond) do { } while (0) #endif +#ifdef CONFIG_DEBUG_VM_PGFLAGS +#define VM_BUG_ON_PGFLAGS(cond, page) VM_BUG_ON_PAGE(cond, page) +#else +#define VM_BUG_ON_PGFLAGS(cond, page) BUILD_BUG_ON_INVALID(cond) +#endif + #endif diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 86c233be1cfc..985fb2c63cb7 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -139,49 +139,101 @@ enum pageflags { #ifndef __GENERATING_BOUNDS_H +struct page; /* forward declaration */ + +static inline struct page *compound_head(struct page *page) +{ + unsigned long head = READ_ONCE(page->compound_head); + + if (unlikely(head & 1)) + return (struct page *) (head - 1); + return page; +} + +static inline int PageTail(struct page *page) +{ + return READ_ONCE(page->compound_head) & 1; +} + +static inline int PageCompound(struct page *page) +{ + return test_bit(PG_head, &page->flags) || PageTail(page); +} + +/* + * Page flags policies wrt compound pages + * + * PF_ANY: + * the page flag is relevant for small, head and tail pages. + * + * PF_HEAD: + * for compound page all operations related to the page flag applied to + * head page. + * + * PF_NO_TAIL: + * modifications of the page flag must be done on small or head pages, + * checks can be done on tail pages too. + * + * PF_NO_COMPOUND: + * the page flag is not relevant for compound pages. + */ +#define PF_ANY(page, enforce) page +#define PF_HEAD(page, enforce) compound_head(page) +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page);}) +#define PF_NO_COMPOUND(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageCompound(page), page); \ + page;}) + /* * Macros to create function definitions for page flags */ -#define TESTPAGEFLAG(uname, lname) \ -static inline int Page##uname(const struct page *page) \ - { return test_bit(PG_##lname, &page->flags); } +#define TESTPAGEFLAG(uname, lname, policy) \ +static inline int Page##uname(struct page *page) \ + { return test_bit(PG_##lname, &policy(page, 0)->flags); } -#define SETPAGEFLAG(uname, lname) \ +#define SETPAGEFLAG(uname, lname, policy) \ static inline void SetPage##uname(struct page *page) \ - { set_bit(PG_##lname, &page->flags); } + { set_bit(PG_##lname, &policy(page, 1)->flags); } -#define CLEARPAGEFLAG(uname, lname) \ +#define CLEARPAGEFLAG(uname, lname, policy) \ static inline void ClearPage##uname(struct page *page) \ - { clear_bit(PG_##lname, &page->flags); } + { clear_bit(PG_##lname, &policy(page, 1)->flags); } -#define __SETPAGEFLAG(uname, lname) \ +#define __SETPAGEFLAG(uname, lname, policy) \ static inline void __SetPage##uname(struct page *page) \ - { __set_bit(PG_##lname, &page->flags); } + { __set_bit(PG_##lname, &policy(page, 1)->flags); } -#define __CLEARPAGEFLAG(uname, lname) \ +#define __CLEARPAGEFLAG(uname, lname, policy) \ static inline void __ClearPage##uname(struct page *page) \ - { __clear_bit(PG_##lname, &page->flags); } + { __clear_bit(PG_##lname, &policy(page, 1)->flags); } -#define TESTSETFLAG(uname, lname) \ +#define TESTSETFLAG(uname, lname, policy) \ static inline int TestSetPage##uname(struct page *page) \ - { return test_and_set_bit(PG_##lname, &page->flags); } + { return test_and_set_bit(PG_##lname, &policy(page, 1)->flags); } -#define TESTCLEARFLAG(uname, lname) \ +#define TESTCLEARFLAG(uname, lname, policy) \ static inline int TestClearPage##uname(struct page *page) \ - { return test_and_clear_bit(PG_##lname, &page->flags); } + { return test_and_clear_bit(PG_##lname, &policy(page, 1)->flags); } -#define __TESTCLEARFLAG(uname, lname) \ +#define __TESTCLEARFLAG(uname, lname, policy) \ static inline int __TestClearPage##uname(struct page *page) \ - { return __test_and_clear_bit(PG_##lname, &page->flags); } + { return __test_and_clear_bit(PG_##lname, &policy(page, 1)->flags); } -#define PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \ - SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname) +#define PAGEFLAG(uname, lname, policy) \ + TESTPAGEFLAG(uname, lname, policy) \ + SETPAGEFLAG(uname, lname, policy) \ + CLEARPAGEFLAG(uname, lname, policy) -#define __PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \ - __SETPAGEFLAG(uname, lname) __CLEARPAGEFLAG(uname, lname) +#define __PAGEFLAG(uname, lname, policy) \ + TESTPAGEFLAG(uname, lname, policy) \ + __SETPAGEFLAG(uname, lname, policy) \ + __CLEARPAGEFLAG(uname, lname, policy) -#define TESTSCFLAG(uname, lname) \ - TESTSETFLAG(uname, lname) TESTCLEARFLAG(uname, lname) +#define TESTSCFLAG(uname, lname, policy) \ + TESTSETFLAG(uname, lname, policy) \ + TESTCLEARFLAG(uname, lname, policy) #define TESTPAGEFLAG_FALSE(uname) \ static inline int Page##uname(const struct page *page) { return 0; } @@ -210,28 +262,28 @@ static inline int __TestClearPage##uname(struct page *page) { return 0; } #define TESTSCFLAG_FALSE(uname) \ TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname) -struct page; /* forward declaration */ - -TESTPAGEFLAG(Locked, locked) -PAGEFLAG(Error, error) TESTCLEARFLAG(Error, error) -PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced) - __SETPAGEFLAG(Referenced, referenced) -PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty) -PAGEFLAG(LRU, lru) __CLEARPAGEFLAG(LRU, lru) -PAGEFLAG(Active, active) __CLEARPAGEFLAG(Active, active) - TESTCLEARFLAG(Active, active) -__PAGEFLAG(Slab, slab) -PAGEFLAG(Checked, checked) /* Used by some filesystems */ -PAGEFLAG(Pinned, pinned) TESTSCFLAG(Pinned, pinned) /* Xen */ -PAGEFLAG(SavePinned, savepinned); /* Xen */ -PAGEFLAG(Foreign, foreign); /* Xen */ -PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved) -PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked) - __SETPAGEFLAG(SwapBacked, swapbacked) - -__PAGEFLAG(SlobFree, slob_free) +__PAGEFLAG(Locked, locked, PF_NO_TAIL) +PAGEFLAG(Error, error, PF_ANY) TESTCLEARFLAG(Error, error, PF_ANY) +PAGEFLAG(Referenced, referenced, PF_ANY) TESTCLEARFLAG(Referenced, referenced, PF_ANY) + __SETPAGEFLAG(Referenced, referenced, PF_ANY) +PAGEFLAG(Dirty, dirty, PF_ANY) TESTSCFLAG(Dirty, dirty, PF_ANY) + __CLEARPAGEFLAG(Dirty, dirty, PF_ANY) +PAGEFLAG(LRU, lru, PF_ANY) __CLEARPAGEFLAG(LRU, lru, PF_ANY) +PAGEFLAG(Active, active, PF_ANY) __CLEARPAGEFLAG(Active, active, PF_ANY) + TESTCLEARFLAG(Active, active, PF_ANY) +__PAGEFLAG(Slab, slab, PF_ANY) +PAGEFLAG(Checked, checked, PF_ANY) /* Used by some filesystems */ +PAGEFLAG(Pinned, pinned, PF_ANY) TESTSCFLAG(Pinned, pinned, PF_ANY) /* Xen */ +PAGEFLAG(SavePinned, savepinned, PF_ANY); /* Xen */ +PAGEFLAG(Foreign, foreign, PF_ANY); /* Xen */ +PAGEFLAG(Reserved, reserved, PF_ANY) __CLEARPAGEFLAG(Reserved, reserved, PF_ANY) +PAGEFLAG(SwapBacked, swapbacked, PF_ANY) + __CLEARPAGEFLAG(SwapBacked, swapbacked, PF_ANY) + __SETPAGEFLAG(SwapBacked, swapbacked, PF_ANY) + +__PAGEFLAG(SlobFree, slob_free, PF_ANY) #ifdef CONFIG_ZCACHE -PAGEFLAG(WasActive, was_active) +PAGEFLAG(WasActive, was_active, PF_ANY) #else PAGEFLAG_FALSE(WasActive) #endif @@ -241,21 +293,22 @@ PAGEFLAG_FALSE(WasActive) * for its own purposes. * - PG_private and PG_private_2 cause releasepage() and co to be invoked */ -PAGEFLAG(Private, private) __SETPAGEFLAG(Private, private) - __CLEARPAGEFLAG(Private, private) -PAGEFLAG(Private2, private_2) TESTSCFLAG(Private2, private_2) -PAGEFLAG(OwnerPriv1, owner_priv_1) TESTCLEARFLAG(OwnerPriv1, owner_priv_1) +PAGEFLAG(Private, private, PF_ANY) __SETPAGEFLAG(Private, private, PF_ANY) + __CLEARPAGEFLAG(Private, private, PF_ANY) +PAGEFLAG(Private2, private_2, PF_ANY) TESTSCFLAG(Private2, private_2, PF_ANY) +PAGEFLAG(OwnerPriv1, owner_priv_1, PF_ANY) + TESTCLEARFLAG(OwnerPriv1, owner_priv_1, PF_ANY) /* * Only test-and-set exist for PG_writeback. The unconditional operators are * risky: they bypass page accounting. */ -TESTPAGEFLAG(Writeback, writeback) TESTSCFLAG(Writeback, writeback) -PAGEFLAG(MappedToDisk, mappedtodisk) +TESTPAGEFLAG(Writeback, writeback, PF_ANY) TESTSCFLAG(Writeback, writeback, PF_ANY) +PAGEFLAG(MappedToDisk, mappedtodisk, PF_ANY) /* PG_readahead is only used for reads; PG_reclaim is only for writes */ -PAGEFLAG(Reclaim, reclaim) TESTCLEARFLAG(Reclaim, reclaim) -PAGEFLAG(Readahead, reclaim) TESTCLEARFLAG(Readahead, reclaim) +PAGEFLAG(Reclaim, reclaim, PF_ANY) TESTCLEARFLAG(Reclaim, reclaim, PF_ANY) +PAGEFLAG(Readahead, reclaim, PF_ANY) TESTCLEARFLAG(Readahead, reclaim, PF_ANY) #ifdef CONFIG_HIGHMEM /* @@ -268,31 +321,32 @@ PAGEFLAG_FALSE(HighMem) #endif #ifdef CONFIG_SWAP -PAGEFLAG(SwapCache, swapcache) +PAGEFLAG(SwapCache, swapcache, PF_ANY) #else PAGEFLAG_FALSE(SwapCache) #endif -PAGEFLAG(Unevictable, unevictable) __CLEARPAGEFLAG(Unevictable, unevictable) - TESTCLEARFLAG(Unevictable, unevictable) +PAGEFLAG(Unevictable, unevictable, PF_ANY) + __CLEARPAGEFLAG(Unevictable, unevictable, PF_ANY) + TESTCLEARFLAG(Unevictable, unevictable, PF_ANY) #ifdef CONFIG_MMU -PAGEFLAG(Mlocked, mlocked) __CLEARPAGEFLAG(Mlocked, mlocked) - TESTSCFLAG(Mlocked, mlocked) __TESTCLEARFLAG(Mlocked, mlocked) +PAGEFLAG(Mlocked, mlocked, PF_ANY) __CLEARPAGEFLAG(Mlocked, mlocked, PF_ANY) + TESTSCFLAG(Mlocked, mlocked, PF_ANY) __TESTCLEARFLAG(Mlocked, mlocked, PF_ANY) #else PAGEFLAG_FALSE(Mlocked) __CLEARPAGEFLAG_NOOP(Mlocked) TESTSCFLAG_FALSE(Mlocked) __TESTCLEARFLAG_FALSE(Mlocked) #endif #ifdef CONFIG_ARCH_USES_PG_UNCACHED -PAGEFLAG(Uncached, uncached) +PAGEFLAG(Uncached, uncached, PF_ANY) #else PAGEFLAG_FALSE(Uncached) #endif #ifdef CONFIG_MEMORY_FAILURE -PAGEFLAG(HWPoison, hwpoison) -TESTSCFLAG(HWPoison, hwpoison) +PAGEFLAG(HWPoison, hwpoison, PF_ANY) +TESTSCFLAG(HWPoison, hwpoison, PF_ANY) #define __PG_HWPOISON (1UL << PG_hwpoison) #else PAGEFLAG_FALSE(HWPoison) @@ -300,10 +354,10 @@ PAGEFLAG_FALSE(HWPoison) #endif #if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) -TESTPAGEFLAG(Young, young) -SETPAGEFLAG(Young, young) -TESTCLEARFLAG(Young, young) -PAGEFLAG(Idle, idle) +TESTPAGEFLAG(Young, young, PF_ANY) +SETPAGEFLAG(Young, young, PF_ANY) +TESTCLEARFLAG(Young, young, PF_ANY) +PAGEFLAG(Idle, idle, PF_ANY) #endif /* @@ -397,7 +451,7 @@ static inline void SetPageUptodate(struct page *page) set_bit(PG_uptodate, &(page)->flags); } -CLEARPAGEFLAG(Uptodate, uptodate) +CLEARPAGEFLAG(Uptodate, uptodate, PF_ANY) int test_clear_page_writeback(struct page *page); int __test_set_page_writeback(struct page *page, bool keep_write); @@ -417,12 +471,7 @@ static inline void set_page_writeback_keepwrite(struct page *page) test_set_page_writeback_keepwrite(page); } -__PAGEFLAG(Head, head) CLEARPAGEFLAG(Head, head) - -static inline int PageTail(struct page *page) -{ - return READ_ONCE(page->compound_head) & 1; -} +__PAGEFLAG(Head, head, PF_ANY) CLEARPAGEFLAG(Head, head, PF_ANY) static inline void set_compound_head(struct page *page, struct page *head) { @@ -434,20 +483,6 @@ static inline void clear_compound_head(struct page *page) WRITE_ONCE(page->compound_head, 0); } -static inline struct page *compound_head(struct page *page) -{ - unsigned long head = READ_ONCE(page->compound_head); - - if (unlikely(head & 1)) - return (struct page *) (head - 1); - return page; -} - -static inline int PageCompound(struct page *page) -{ - return PageHead(page) || PageTail(page); - -} #ifdef CONFIG_TRANSPARENT_HUGEPAGE static inline void ClearPageCompound(struct page *page) { @@ -573,7 +608,7 @@ static inline void __ClearPageBalloon(struct page *page) atomic_set(&page->_mapcount, -1); } -__PAGEFLAG(Isolated, isolated); +__PAGEFLAG(Isolated, isolated, PF_ANY); /* * If network-based swap is enabled, sl*b must keep track of whether pages @@ -652,6 +687,10 @@ static inline int page_has_private(struct page *page) return !!(page->flags & PAGE_FLAGS_PRIVATE); } +#undef PF_ANY +#undef PF_HEAD +#undef PF_NO_TAIL +#undef PF_NO_COMPOUND #endif /* !__GENERATING_BOUNDS_H */ #endif /* PAGE_FLAGS_H */ diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 443a063e6af8..d2f4a732b3e8 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -441,18 +441,9 @@ extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm, unsigned int flags); extern void unlock_page(struct page *page); -static inline void __set_page_locked(struct page *page) -{ - __set_bit(PG_locked, &page->flags); -} - -static inline void __clear_page_locked(struct page *page) -{ - __clear_bit(PG_locked, &page->flags); -} - static inline int trylock_page(struct page *page) { + page = compound_head(page); return (likely(!test_and_set_bit_lock(PG_locked, &page->flags))); } @@ -505,9 +496,9 @@ extern int wait_on_page_bit_killable_timeout(struct page *page, static inline int wait_on_page_locked_killable(struct page *page) { - if (PageLocked(page)) - return wait_on_page_bit_killable(page, PG_locked); - return 0; + if (!PageLocked(page)) + return 0; + return wait_on_page_bit_killable(compound_head(page), PG_locked); } extern wait_queue_head_t *page_waitqueue(struct page *page); @@ -526,7 +517,7 @@ static inline void wake_up_page(struct page *page, int bit) static inline void wait_on_page_locked(struct page *page) { if (PageLocked(page)) - wait_on_page_bit(page, PG_locked); + wait_on_page_bit(compound_head(page), PG_locked); } /* @@ -672,17 +663,17 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask); /* * Like add_to_page_cache_locked, but used to add newly allocated pages: - * the page is new, so we can just run __set_page_locked() against it. + * the page is new, so we can just run __SetPageLocked() against it. */ static inline int add_to_page_cache(struct page *page, struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask) { int error; - __set_page_locked(page); + __SetPageLocked(page); error = add_to_page_cache_locked(page, mapping, offset, gfp_mask); if (unlikely(error)) - __clear_page_locked(page); + __ClearPageLocked(page); return error; } diff --git a/include/linux/qdsp6v2/audio-anc-dev-mgr.h b/include/linux/qdsp6v2/audio-anc-dev-mgr.h index dfa6752bc31b..b0ece2dbb239 100644 --- a/include/linux/qdsp6v2/audio-anc-dev-mgr.h +++ b/include/linux/qdsp6v2/audio-anc-dev-mgr.h @@ -39,6 +39,8 @@ int msm_anc_dev_stop(void); int msm_anc_dev_set_info(void *info_p, int32_t anc_cmd); +int msm_anc_dev_get_info(void *info_p, int32_t anc_cmd); + int msm_anc_dev_create(struct platform_device *pdev); int msm_anc_dev_destroy(struct platform_device *pdev); diff --git a/include/linux/qdsp6v2/sdsp_anc.h b/include/linux/qdsp6v2/sdsp_anc.h index 3b236e827e3d..5c1b7055c1d5 100644 --- a/include/linux/qdsp6v2/sdsp_anc.h +++ b/include/linux/qdsp6v2/sdsp_anc.h @@ -15,7 +15,6 @@ #include <sound/q6afe-v2.h> #include <sound/apr_audio-v2.h> - #define AUD_MSVC_MODULE_AUDIO_DEV_RESOURCE_SHARE 0x0001028A #define AUD_MSVC_PARAM_ID_PORT_SHARE_RESOURCE_CONFIG 0x00010297 #define AUD_MSVC_API_VERSION_SHARE_RESOURCE_CONFIG 0x1 @@ -23,8 +22,6 @@ #define AUD_MSVC_PARAM_ID_DEV_ANC_REFS_CONFIG 0x00010286 #define AUD_MSVC_API_VERSION_DEV_ANC_REFS_CONFIG 0x1 #define AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO 0x00010234 -#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM 0x00010235 -#define AUD_MSVC_API_VERSION_DEV_ANC_ALGO_RPM 0x1 struct aud_msvc_port_param_data_v2 { /* ID of the module to be configured. @@ -148,7 +145,7 @@ struct aud_msvc_port_cmd_get_param_v2 { } __packed; struct aud_audioif_config_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; union afe_port_config port; @@ -162,13 +159,6 @@ struct aud_msvc_param_id_dev_share_resource_cfg { u32 lpm_length; } __packed; - -struct aud_msvc_param_id_dev_anc_algo_rpm { - u32 minor_version; - u32 rpm; -} __packed; - - struct aud_msvc_param_id_dev_anc_refs_cfg { u32 minor_version; u16 port_id; @@ -177,65 +167,20 @@ struct aud_msvc_param_id_dev_anc_refs_cfg { u32 bit_width; } __packed; - struct anc_share_resource_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_share_resource_cfg resource; } __packed; - struct anc_config_ref_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_anc_refs_cfg refs; } __packed; - - -struct anc_set_rpm_command { - struct apr_hdr hdr; - struct aud_msvc_port_cmd_set_param_v2 param; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_rpm set_rpm; -} __packed; - -struct anc_get_rpm_command { - struct apr_hdr hdr; - struct aud_msvc_port_cmd_get_param_v2 param; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_rpm get_rpm; -} __packed; - -struct anc_get_rpm_resp { - uint32_t status; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_rpm res_rpm; -} __packed; - -#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_BYPASS_MODE 0x0001029B - -#define AUD_MSVC_API_VERSION_DEV_ANC_ALGO_BYPASS_MODE 0x1 - -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_NO 0x0 -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_REFS_TO_ANC_SPKR 0x1 -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_ANC_MIC_TO_ANC_SPKR 0x2 -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_REFS_MIXED_ANC_MIC_TO_ANC_SPKR 0x3 - -struct aud_msvc_param_id_dev_anc_algo_bypass_mode { - uint32_t minor_version; - uint32_t bypass_mode; -} __packed; - -struct anc_set_bypass_mode_command { - struct apr_hdr hdr; - struct aud_msvc_port_cmd_set_param_v2 param; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_bypass_mode set_bypass_mode; -} __packed; - #define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID 0x0001023A struct aud_msvc_param_id_dev_anc_algo_module_id { @@ -244,7 +189,7 @@ struct aud_msvc_param_id_dev_anc_algo_module_id { } __packed; struct anc_set_algo_module_id_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_anc_algo_module_id set_algo_module_id; @@ -269,13 +214,37 @@ struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info { } __packed; struct anc_set_mic_spkr_layout_info_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info set_mic_spkr_layout; } __packed; +struct anc_set_algo_module_cali_data_command { + struct apr_hdr hdr; + struct aud_msvc_port_cmd_set_param_v2 param; + struct aud_msvc_port_param_data_v2 pdata; + /* + * calibration data payload followed + */ +} __packed; + +struct anc_get_algo_module_cali_data_command { + struct apr_hdr hdr; + struct aud_msvc_port_cmd_get_param_v2 param; + struct aud_msvc_port_param_data_v2 pdata; + /* + * calibration data payload followed + */ +} __packed; + +struct anc_get_algo_module_cali_data_resp { + uint32_t status; + struct aud_msvc_port_param_data_v2 pdata; + uint32_t payload[128]; +} __packed; + int anc_if_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port); int anc_if_tdm_port_stop(u16 port_id); @@ -286,15 +255,15 @@ int anc_if_share_resource(u16 port_id, u16 rddma_idx, u16 wrdma_idx, int anc_if_config_ref(u16 port_id, u32 sample_rate, u32 bit_width, u16 num_channel); -int anc_if_set_rpm(u16 port_id, u32 rpm); - -int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode); - int anc_if_set_algo_module_id(u16 port_id, u32 module_id); int anc_if_set_anc_mic_spkr_layout(u16 port_id, struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p); +int anc_if_set_algo_module_cali_data(u16 port_id, void *data_p); + +int anc_if_get_algo_module_cali_data(u16 port_id, void *data_p); + int anc_if_shared_mem_map(void); int anc_if_shared_mem_unmap(void); diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 5ed540986019..0c94d17a4642 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -45,19 +45,17 @@ static inline void INIT_LIST_HEAD_RCU(struct list_head *list) * This is only for internal list manipulation where we know * the prev/next entries already! */ -#ifndef CONFIG_DEBUG_LIST static inline void __list_add_rcu(struct list_head *new, struct list_head *prev, struct list_head *next) { + if (!__list_add_valid(new, prev, next)) + return; + new->next = next; new->prev = prev; rcu_assign_pointer(list_next_rcu(prev), new); next->prev = new; } -#else -void __list_add_rcu(struct list_head *new, - struct list_head *prev, struct list_head *next); -#endif /** * list_add_rcu - add a new entry to rcu-protected list diff --git a/include/linux/sched.h b/include/linux/sched.h index 5fe8c3dfd60f..8f6894c6e83c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1726,7 +1726,7 @@ struct task_struct { struct mm_struct *mm, *active_mm; /* per-thread vma caching */ - u32 vmacache_seqnum; + u64 vmacache_seqnum; struct vm_area_struct *vmacache[VMACACHE_SIZE]; #if defined(SPLIT_RSS_COUNTING) struct task_rss_stat rss_stat; diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index c2b66a277e98..5d2779aa4bbe 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -205,6 +205,26 @@ extern struct trace_event_functions exit_syscall_print_funcs; } \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) +/* + * Called before coming back to user-mode. Returning to user-mode with an + * address limit different than USER_DS can allow to overwrite kernel memory. + */ +static inline void addr_limit_user_check(void) +{ +#ifdef TIF_FSCHECK + if (!test_thread_flag(TIF_FSCHECK)) + return; +#endif + + if (CHECK_DATA_CORRUPTION(!segment_eq(get_fs(), USER_DS), + "Invalid address limit on user-mode return")) + force_sig(SIGKILL, current); + +#ifdef TIF_FSCHECK + clear_thread_flag(TIF_FSCHECK); +#endif +} + asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr); asmlinkage long sys_time(time_t __user *tloc); diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h index 056b4e5830a6..d31afe5d790d 100644 --- a/include/linux/vm_event_item.h +++ b/include/linux/vm_event_item.h @@ -89,7 +89,6 @@ enum vm_event_item { PGPGIN, PGPGOUT, PGPGOUTCLEAN, PSWPIN, PSWPOUT, #ifdef CONFIG_DEBUG_VM_VMACACHE VMACACHE_FIND_CALLS, VMACACHE_FIND_HITS, - VMACACHE_FULL_FLUSHES, #endif NR_VM_EVENT_ITEMS }; diff --git a/include/linux/vmacache.h b/include/linux/vmacache.h index c3fa0fd43949..4f58ff2dacd6 100644 --- a/include/linux/vmacache.h +++ b/include/linux/vmacache.h @@ -15,7 +15,6 @@ static inline void vmacache_flush(struct task_struct *tsk) memset(tsk->vmacache, 0, sizeof(tsk->vmacache)); } -extern void vmacache_flush_all(struct mm_struct *mm); extern void vmacache_update(unsigned long addr, struct vm_area_struct *newvma); extern struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr); @@ -29,10 +28,6 @@ extern struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm, static inline void vmacache_invalidate(struct mm_struct *mm) { mm->vmacache_seqnum++; - - /* deal with overflows */ - if (unlikely(mm->vmacache_seqnum == 0)) - vmacache_flush_all(mm); } #endif /* __LINUX_VMACACHE_H */ diff --git a/include/net/cnss2.h b/include/net/cnss2.h index e06f0b670d90..7ca407f6b606 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -192,6 +192,9 @@ extern void cnss_lock_pm_sem(struct device *dev); extern void cnss_release_pm_sem(struct device *dev); extern int cnss_auto_suspend(struct device *dev); extern int cnss_auto_resume(struct device *dev); +extern int cnss_pci_force_wake_request(struct device *dev); +extern int cnss_pci_is_device_awake(struct device *dev); +extern int cnss_pci_force_wake_release(struct device *dev); extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, uint32_t *user_base_data, diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 30dbd1c34335..583ebc4616e9 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -62,6 +62,15 @@ struct drm_msm_timespec { __s64 tv_nsec; /* nanoseconds */ }; +/* From CEA.861.3 */ +#define HDR_EOTF_SMTPE_ST2084 0x2 +#define HDR_EOTF_HLG 0x3 + +/* hdr hdmi state takes possible values of 0, 1 and 2 respectively */ +#define DRM_MSM_HDR_DISABLE 0 +#define DRM_MSM_HDR_ENABLE 1 +#define DRM_MSM_HDR_RESET 2 + /* * HDR Metadata * These are defined as per EDID spec and shall be used by the sink diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 5539933b3491..bd0da0e992b8 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -246,6 +246,15 @@ struct binder_node_debug_info { __u32 has_weak_ref; }; +struct binder_node_info_for_ref { + __u32 handle; + __u32 strong_count; + __u32 weak_count; + __u32 reserved1; + __u32 reserved2; + __u32 reserved3; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -254,6 +263,7 @@ struct binder_node_debug_info { #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) +#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) /* * NOTE: Two special error codes you should check for when calling diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index cd1629170103..08f47e0e9f8d 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -819,13 +819,13 @@ struct ethtool_rx_flow_spec { static inline __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie) { return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie; -}; +} static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie) { return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; -}; +} /** * struct ethtool_rxnfc - command to get or set RX flow classification rules diff --git a/include/uapi/linux/msm_audio_anc.h b/include/uapi/linux/msm_audio_anc.h index d628f7ce9267..87701fd8ee3a 100644 --- a/include/uapi/linux/msm_audio_anc.h +++ b/include/uapi/linux/msm_audio_anc.h @@ -21,6 +21,8 @@ /* room for ANC_CMD define extend */ #define ANC_CMD_MAX 0xFF +#define ANC_CALIBRATION_PAYLOAD_SIZE_MAX 100 + struct audio_anc_header { int32_t data_size; int32_t version; @@ -35,14 +37,23 @@ struct audio_anc_rpm_info { struct audio_anc_bypass_mode { int32_t mode; }; - struct audio_anc_algo_module_info { int32_t module_id; }; +struct audio_anc_algo_calibration_header { + uint32_t module_id; + uint32_t param_id; + uint32_t payload_size; +}; + +struct audio_anc_algo_calibration_body { + int32_t payload[ANC_CALIBRATION_PAYLOAD_SIZE_MAX]; +}; + struct audio_anc_algo_calibration_info { - int32_t payload_size; - /* num bytes of payload specificed in payload_size followed */ + struct audio_anc_algo_calibration_header cali_header; + struct audio_anc_algo_calibration_body cali_body; }; union audio_anc_data { diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index 13bb8b79359a..005fb8284524 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -322,6 +322,8 @@ enum kgsl_timestamp_type { #define KGSL_PROP_DEVICE_QDSS_STM 0x19 #define KGSL_PROP_DEVICE_QTIMER 0x20 #define KGSL_PROP_IB_TIMEOUT 0x21 +#define KGSL_PROP_SECURE_BUFFER_ALIGNMENT 0x23 +#define KGSL_PROP_SECURE_CTXT_SUPPORT 0x24 struct kgsl_shadowprop { unsigned long gpuaddr; diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index a162661c9d60..f45a9a5d3e47 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -419,6 +419,13 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) struct path parent_path; int h, ret = 0; + /* + * When we will be calling audit_add_to_parent, krule->watch might have + * been updated and watch might have been freed. + * So we need to keep a reference of watch. + */ + audit_get_watch(watch); + mutex_unlock(&audit_filter_mutex); /* Avoid calling path_lookup under audit_filter_mutex. */ @@ -427,8 +434,10 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) /* caller expects mutex locked */ mutex_lock(&audit_filter_mutex); - if (ret) + if (ret) { + audit_put_watch(watch); return ret; + } /* either find an old parent or attach a new one */ parent = audit_find_parent(d_backing_inode(parent_path.dentry)); @@ -446,6 +455,7 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) *list = &audit_inode_hash[h]; error: path_put(&parent_path); + audit_put_watch(watch); return ret; } diff --git a/kernel/fork.c b/kernel/fork.c index caa23ca489bb..77a21c3d02e3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1142,7 +1142,9 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) return -ENOMEM; atomic_set(&sig->count, 1); + spin_lock_irq(¤t->sighand->siglock); memcpy(sig->action, current->sighand->action, sizeof(sig->action)); + spin_unlock_irq(¤t->sighand->siglock); return 0; } @@ -1370,6 +1372,18 @@ static struct task_struct *copy_process(unsigned long clone_flags, cpufreq_task_times_init(p); + /* + * This _must_ happen before we call free_task(), i.e. before we jump + * to any of the bad_fork_* labels. This is to avoid freeing + * p->set_child_tid which is (ab)used as a kthread's data pointer for + * kernel threads (PF_KTHREAD). + */ + p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; + /* + * Clear TID on mm_release()? + */ + p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL; + ftrace_graph_init_task(p); rt_mutex_init_task(p); @@ -1531,11 +1545,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, } } - p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; - /* - * Clear TID on mm_release()? - */ - p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL; #ifdef CONFIG_BLOCK p->plug = NULL; #endif diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index e0449956298e..825ae448c7a9 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -338,7 +338,6 @@ void handle_nested_irq(unsigned int irq) raw_spin_lock_irq(&desc->lock); desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(desc); action = desc->action; if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) { @@ -346,6 +345,7 @@ void handle_nested_irq(unsigned int irq) goto out_unlock; } + kstat_incr_irqs_this_cpu(desc); irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); raw_spin_unlock_irq(&desc->lock); @@ -412,13 +412,13 @@ void handle_simple_irq(struct irq_desc *desc) goto out_unlock; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(desc); if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { desc->istate |= IRQS_PENDING; goto out_unlock; } + kstat_incr_irqs_this_cpu(desc); handle_irq_event(desc); out_unlock: @@ -462,7 +462,6 @@ void handle_level_irq(struct irq_desc *desc) goto out_unlock; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(desc); /* * If its disabled or no action available @@ -473,6 +472,7 @@ void handle_level_irq(struct irq_desc *desc) goto out_unlock; } + kstat_incr_irqs_this_cpu(desc); handle_irq_event(desc); cond_unmask_irq(desc); @@ -532,7 +532,6 @@ void handle_fasteoi_irq(struct irq_desc *desc) goto out; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(desc); /* * If its disabled or no action available @@ -544,6 +543,7 @@ void handle_fasteoi_irq(struct irq_desc *desc) goto out; } + kstat_incr_irqs_this_cpu(desc); if (desc->istate & IRQS_ONESHOT) mask_irq(desc); diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 75c950ede9c7..1be33caf157d 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -511,38 +511,30 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) unsigned long flags; /* - * If a spinner is present, there is a chance that the load of - * rwsem_has_spinner() in rwsem_wake() can be reordered with - * respect to decrement of rwsem count in __up_write() leading - * to wakeup being missed. - * - * spinning writer up_write caller - * --------------- ----------------------- - * [S] osq_unlock() [L] osq - * spin_lock(wait_lock) - * sem->count=0xFFFFFFFF00000001 - * +0xFFFFFFFF00000000 - * count=sem->count - * MB - * sem->count=0xFFFFFFFE00000001 - * -0xFFFFFFFF00000001 - * RMB - * spin_trylock(wait_lock) - * return - * rwsem_try_write_lock(count) - * spin_unlock(wait_lock) - * schedule() - * - * Reordering of atomic_long_sub_return_release() in __up_write() - * and rwsem_has_spinner() in rwsem_wake() can cause missing of - * wakeup in up_write() context. In spinning writer, sem->count - * and local variable count is 0XFFFFFFFE00000001. It would result - * in rwsem_try_write_lock() failing to acquire rwsem and spinning - * writer going to sleep in rwsem_down_write_failed(). - * - * The smp_rmb() here is to make sure that the spinner state is - * consulted after sem->count is updated in up_write context. - */ + * __rwsem_down_write_failed_common(sem) + * rwsem_optimistic_spin(sem) + * osq_unlock(sem->osq) + * ... + * atomic_long_add_return(&sem->count) + * + * - VS - + * + * __up_write() + * if (atomic_long_sub_return_release(&sem->count) < 0) + * rwsem_wake(sem) + * osq_is_locked(&sem->osq) + * + * And __up_write() must observe !osq_is_locked() when it observes the + * atomic_long_add_return() in order to not miss a wakeup. + * + * This boils down to: + * + * [S.rel] X = 1 [RmW] r0 = (Y += 0) + * MB RMB + * [RmW] Y += 1 [L] r1 = X + * + * exists (r0=1 /\ r1=0) + */ smp_rmb(); /* diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2d8447a1674b..17fcf03bb384 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -588,6 +588,14 @@ config DEBUG_VM_RB If unsure, say N. +config DEBUG_VM_PGFLAGS + bool "Debug page-flags operations" + depends on DEBUG_VM + help + Enables extra validation on page flags operations. + + If unsure, say N. + config DEBUG_VIRTUAL bool "Debug VM translations" depends on DEBUG_KERNEL && X86 @@ -2000,6 +2008,16 @@ config PANIC_ON_DATA_CORRUPTION recoverable data corruption scenarios to system-halting panics, for easier detection and debug. +config BUG_ON_DATA_CORRUPTION + bool "Trigger a BUG when data corruption is detected" + select CONFIG_DEBUG_LIST + help + Select this option if the kernel should BUG when it encounters + data corruption in kernel memory structures when they get checked + for validity. + + If unsure, say N. + source "samples/Kconfig" source "lib/Kconfig.kgdb" diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 9ddee8c271a7..04e3bb84560e 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -297,9 +297,12 @@ static void debug_object_is_on_stack(void *addr, int onstack) limit++; if (is_on_stack) - pr_warn("object is on stack, but not annotated\n"); + pr_warn("object %p is on stack %p, but NOT annotated.\n", addr, + task_stack_page(current)); else - pr_warn("object is not on stack, but annotated\n"); + pr_warn("object %p is NOT on stack %p, but annotated.\n", addr, + task_stack_page(current)); + WARN_ON(1); } diff --git a/lib/list_debug.c b/lib/list_debug.c index 8cf180bfaabe..18b872cc4242 100644 --- a/lib/list_debug.c +++ b/lib/list_debug.c @@ -2,8 +2,7 @@ * Copyright 2006, Red Hat, Inc., Dave Jones * Released under the General Public License (GPL). * - * This file contains the linked list implementations for - * DEBUG_LIST. + * This file contains the linked list validation for DEBUG_LIST. */ #include <linux/export.h> @@ -14,94 +13,51 @@ #include <linux/bug.h> /* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! + * Check that the data structures for the list manipulations are reasonably + * valid. Failures here indicate memory corruption (and possibly an exploit + * attempt). */ -void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) +bool __list_add_valid(struct list_head *new, struct list_head *prev, + struct list_head *next) { - WARN(next->prev != prev, - "list_add corruption. next->prev should be " - "prev (%p), but was %p. (next=%p).\n", - prev, next->prev, next); - WARN(prev->next != next, - "list_add corruption. prev->next should be " - "next (%p), but was %p. (prev=%p).\n", - next, prev->next, prev); - WARN(new == prev || new == next, - "list_add double add: new=%p, prev=%p, next=%p.\n", - new, prev, next); - - BUG_ON((prev->next != next || next->prev != prev || - new == prev || new == next) && PANIC_CORRUPTION); - - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + if (CHECK_DATA_CORRUPTION(next->prev != prev, + "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", + prev, next->prev, next) || + CHECK_DATA_CORRUPTION(prev->next != next, + "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", + next, prev->next, prev) || + CHECK_DATA_CORRUPTION(new == prev || new == next, + "list_add double add: new=%p, prev=%p, next=%p.\n", + new, prev, next)) + return false; + + return true; } -EXPORT_SYMBOL(__list_add); +EXPORT_SYMBOL(__list_add_valid); -void __list_del_entry(struct list_head *entry) +bool __list_del_entry_valid(struct list_head *entry) { struct list_head *prev, *next; prev = entry->prev; next = entry->next; - if (WARN(next == LIST_POISON1, - "list_del corruption, %p->next is LIST_POISON1 (%p)\n", - entry, LIST_POISON1) || - WARN(prev == LIST_POISON2, - "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", - entry, LIST_POISON2) || - WARN(prev->next != entry, - "list_del corruption. prev->next should be %p, " - "but was %p\n", entry, prev->next) || - WARN(next->prev != entry, - "list_del corruption. next->prev should be %p, " - "but was %p\n", entry, next->prev)) { - BUG_ON(PANIC_CORRUPTION); - return; - } - - __list_del(prev, next); -} -EXPORT_SYMBOL(__list_del_entry); - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -void list_del(struct list_head *entry) -{ - __list_del_entry(entry); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -EXPORT_SYMBOL(list_del); + if (CHECK_DATA_CORRUPTION(next == LIST_POISON1, + "list_del corruption, %p->next is LIST_POISON1 (%p)\n", + entry, LIST_POISON1) || + CHECK_DATA_CORRUPTION(prev == LIST_POISON2, + "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", + entry, LIST_POISON2) || + CHECK_DATA_CORRUPTION(prev->next != entry, + "list_del corruption. prev->next should be %p, but was %p\n", + entry, prev->next) || + CHECK_DATA_CORRUPTION(next->prev != entry, + "list_del corruption. next->prev should be %p, but was %p\n", + entry, next->prev)) + return false; + + return true; -/* - * RCU variants. - */ -void __list_add_rcu(struct list_head *new, - struct list_head *prev, struct list_head *next) -{ - WARN(next->prev != prev, - "list_add_rcu corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", - prev, next->prev, next); - WARN(prev->next != next, - "list_add_rcu corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", - next, prev->next, prev); - new->next = next; - new->prev = prev; - rcu_assign_pointer(list_next_rcu(prev), new); - next->prev = new; } -EXPORT_SYMBOL(__list_add_rcu); +EXPORT_SYMBOL(__list_del_entry_valid); diff --git a/mm/debug.c b/mm/debug.c index 3621385c09ac..89ac083ea504 100644 --- a/mm/debug.c +++ b/mm/debug.c @@ -184,7 +184,7 @@ EXPORT_SYMBOL(dump_vma); void dump_mm(const struct mm_struct *mm) { - pr_emerg("mm %p mmap %p seqnum %d task_size %lu\n" + pr_emerg("mm %p mmap %p seqnum %llu task_size %lu\n" #ifdef CONFIG_MMU "get_unmapped_area %p\n" #endif @@ -214,7 +214,7 @@ void dump_mm(const struct mm_struct *mm) #endif "%s", /* This is here to hold the comma */ - mm, mm->mmap, mm->vmacache_seqnum, mm->task_size, + mm, mm->mmap, (long long) mm->vmacache_seqnum, mm->task_size, #ifdef CONFIG_MMU mm->get_unmapped_area, #endif diff --git a/mm/fadvise.c b/mm/fadvise.c index b8a5bc66b0c0..001877e32f0c 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -68,8 +68,12 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice) goto out; } - /* Careful about overflows. Len == 0 means "as much as possible" */ - endbyte = offset + len; + /* + * Careful about overflows. Len == 0 means "as much as possible". Use + * unsigned math because signed overflows are undefined and UBSan + * complains. + */ + endbyte = (u64)offset + (u64)len; if (!len || endbyte < len) endbyte = -1; else diff --git a/mm/filemap.c b/mm/filemap.c index 6aa6f0cc67e1..ea5c7a6e20d2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -689,11 +689,11 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping, void *shadow = NULL; int ret; - __set_page_locked(page); + __SetPageLocked(page); ret = __add_to_page_cache_locked(page, mapping, offset, gfp_mask, &shadow); if (unlikely(ret)) - __clear_page_locked(page); + __ClearPageLocked(page); else { /* * The page might have been evicted from cache only @@ -816,6 +816,7 @@ EXPORT_SYMBOL_GPL(add_page_wait_queue); */ void unlock_page(struct page *page) { + page = compound_head(page); VM_BUG_ON_PAGE(!PageLocked(page), page); clear_bit_unlock(PG_locked, &page->flags); smp_mb__after_atomic(); @@ -883,18 +884,20 @@ EXPORT_SYMBOL_GPL(page_endio); */ void __lock_page(struct page *page) { - DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); + struct page *page_head = compound_head(page); + DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked); - __wait_on_bit_lock(page_waitqueue(page), &wait, bit_wait_io, + __wait_on_bit_lock(page_waitqueue(page_head), &wait, bit_wait_io, TASK_UNINTERRUPTIBLE); } EXPORT_SYMBOL(__lock_page); int __lock_page_killable(struct page *page) { - DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); + struct page *page_head = compound_head(page); + DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked); - return __wait_on_bit_lock(page_waitqueue(page), &wait, + return __wait_on_bit_lock(page_waitqueue(page_head), &wait, bit_wait_io, TASK_KILLABLE); } EXPORT_SYMBOL_GPL(__lock_page_killable); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index d64d48ca789c..67f5a8ca0af1 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1392,12 +1392,12 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, /* Migration could have started since the pmd_trans_migrating check */ if (!page_locked) { + page_nid = -1; if (!get_page_unless_zero(page)) goto out_unlock; spin_unlock(ptl); wait_on_page_locked(page); put_page(page); - page_nid = -1; goto out; } @@ -1989,7 +1989,7 @@ struct page *ksm_might_need_to_copy(struct page *page, SetPageDirty(new_page); __SetPageUptodate(new_page); - __set_page_locked(new_page); + __SetPageLocked(new_page); } return new_page; diff --git a/mm/memory-failure.c b/mm/memory-failure.c index d4271ebc37d0..d5d9839ede9b 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1173,7 +1173,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) /* * We ignore non-LRU pages for good reasons. * - PG_locked is only well defined for LRU pages and a few others - * - to avoid races with __set_page_locked() + * - to avoid races with __SetPageLocked() * - to avoid races with __SetPageSlab*() (and more non-atomic ops) * The check (unnecessarily) ignores LRU pages being isolated and * walked by the page reclaim code, however that's not a big loss. diff --git a/mm/migrate.c b/mm/migrate.c index 921cf12b03ce..879aabed46bb 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1936,7 +1936,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, flush_tlb_range(vma, mmun_start, mmun_end); /* Prepare a page as a migration target */ - __set_page_locked(new_page); + __SetPageLocked(new_page); SetPageSwapBacked(new_page); /* anon mapping, we can simply copy page->mapping to the new page: */ diff --git a/mm/shmem.c b/mm/shmem.c index 79997e8cf807..9bdb044d4dee 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1003,7 +1003,7 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp, copy_highpage(newpage, oldpage); flush_dcache_page(newpage); - __set_page_locked(newpage); + __SetPageLocked(newpage); SetPageUptodate(newpage); SetPageSwapBacked(newpage); set_page_private(newpage, swap_index); @@ -1195,7 +1195,7 @@ repeat: } __SetPageSwapBacked(page); - __set_page_locked(page); + __SetPageLocked(page); if (sgp == SGP_WRITE) __SetPageReferenced(page); diff --git a/mm/slub.c b/mm/slub.c index 675e6efd5c8f..f806a8af741f 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -333,11 +333,13 @@ static inline int oo_objects(struct kmem_cache_order_objects x) */ static __always_inline void slab_lock(struct page *page) { + VM_BUG_ON_PAGE(PageTail(page), page); bit_spin_lock(PG_locked, &page->flags); } static __always_inline void slab_unlock(struct page *page) { + VM_BUG_ON_PAGE(PageTail(page), page); __bit_spin_unlock(PG_locked, &page->flags); } diff --git a/mm/swap_state.c b/mm/swap_state.c index 61039e39e25f..9f49247ef0e6 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -355,7 +355,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, } /* May fail (-ENOMEM) if radix-tree node allocation failed. */ - __set_page_locked(new_page); + __SetPageLocked(new_page); SetPageSwapBacked(new_page); err = __add_to_swap_cache(new_page, entry); if (likely(!err)) { @@ -369,7 +369,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, } radix_tree_preload_end(); ClearPageSwapBacked(new_page); - __clear_page_locked(new_page); + __ClearPageLocked(new_page); /* * add_to_swap_cache() doesn't return -EEXIST, so we can safely * clear SWAP_HAS_CACHE flag. diff --git a/mm/vmacache.c b/mm/vmacache.c index fd09dc9c6812..9c8ff3d4eda9 100644 --- a/mm/vmacache.c +++ b/mm/vmacache.c @@ -6,44 +6,6 @@ #include <linux/vmacache.h> /* - * Flush vma caches for threads that share a given mm. - * - * The operation is safe because the caller holds the mmap_sem - * exclusively and other threads accessing the vma cache will - * have mmap_sem held at least for read, so no extra locking - * is required to maintain the vma cache. - */ -void vmacache_flush_all(struct mm_struct *mm) -{ - struct task_struct *g, *p; - - count_vm_vmacache_event(VMACACHE_FULL_FLUSHES); - - /* - * Single threaded tasks need not iterate the entire - * list of process. We can avoid the flushing as well - * since the mm's seqnum was increased and don't have - * to worry about other threads' seqnum. Current's - * flush will occur upon the next lookup. - */ - if (atomic_read(&mm->mm_users) == 1) - return; - - rcu_read_lock(); - for_each_process_thread(g, p) { - /* - * Only flush the vmacache pointers as the - * mm seqnum is already set and curr's will - * be set upon invalidation when the next - * lookup is done. - */ - if (mm == p->mm) - vmacache_flush(p); - } - rcu_read_unlock(); -} - -/* * This task may be accessing a foreign mm via (for example) * get_user_pages()->find_vma(). The vmacache is task-local and this * task's vmacache pertains to a different mm (ie, its own). There is diff --git a/mm/vmscan.c b/mm/vmscan.c index abeea66bc429..aa1074d3031b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1247,7 +1247,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, * we obviously don't have to worry about waking up a process * waiting on the page lock, because there are no references. */ - __clear_page_locked(page); + __ClearPageLocked(page); free_it: nr_reclaimed++; diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 6018a1c0dc28..2a15b6aa9cdd 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -574,7 +574,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) chan->vq = virtio_find_single_vq(vdev, req_done, "requests"); if (IS_ERR(chan->vq)) { err = PTR_ERR(chan->vq); - goto out_free_vq; + goto out_free_chan; } chan->vq->vdev->priv = chan; spin_lock_init(&chan->lock); @@ -627,6 +627,7 @@ out_free_tag: kfree(tag); out_free_vq: vdev->config->del_vqs(vdev); +out_free_chan: kfree(chan); fail: return err; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index a295b5ec9d4a..e614940c4e98 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -775,7 +775,7 @@ static int hidp_setup_hid(struct hidp_session *session, hid->version = req->version; hid->country = req->country; - strncpy(hid->name, req->name, sizeof(req->name) - 1); + strncpy(hid->name, req->name, sizeof(hid->name)); snprintf(hid->phys, sizeof(hid->phys), "%pMR", &l2cap_pi(session->ctrl_sock->sk)->chan->src); diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 4f6c1862dfd2..6fe2b615518c 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -1763,7 +1763,7 @@ static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, if (itr->app.selector == app->selector && itr->app.protocol == app->protocol && itr->ifindex == ifindex && - (!prio || itr->app.priority == prio)) + ((prio == -1) || itr->app.priority == prio)) return itr; } @@ -1798,7 +1798,8 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) u8 prio = 0; spin_lock_bh(&dcb_lock); - if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) + itr = dcb_app_lookup(app, dev->ifindex, -1); + if (itr) prio = itr->app.priority; spin_unlock_bh(&dcb_lock); @@ -1826,7 +1827,8 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new) spin_lock_bh(&dcb_lock); /* Search for existing match and replace */ - if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) { + itr = dcb_app_lookup(new, dev->ifindex, -1); + if (itr) { if (new->priority) itr->app.priority = new->priority; else { @@ -1859,7 +1861,8 @@ u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) u8 prio = 0; spin_lock_bh(&dcb_lock); - if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) + itr = dcb_app_lookup(app, dev->ifindex, -1); + if (itr) prio |= 1 << itr->app.priority; spin_unlock_bh(&dcb_lock); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4c1c94fa8f08..d270870bf492 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -200,8 +200,9 @@ kill: inet_twsk_deschedule_put(tw); return TCP_TW_SUCCESS; } + } else { + inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN); } - inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN); if (tmp_opt.saw_tstamp) { tcptw->tw_ts_recent = tmp_opt.rcv_tsval; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 060862a6f2f2..ca697f16d2ea 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -470,7 +470,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) } mtu = dst_mtu(dst); - if (!skb->ignore_df && skb->len > mtu) { + if (skb->len > mtu) { skb_dst(skb)->ops->update_pmtu(dst, NULL, skb, mtu); if (skb->protocol == htons(ETH_P_IPV6)) { diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 4a116d766c15..7cc9db38e1b6 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -774,6 +774,13 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return -EINVAL; lock_sock(sk); + + /* Ensure that the socket is not already bound */ + if (self->ias_obj) { + err = -EINVAL; + goto out; + } + #ifdef CONFIG_IRDA_ULTRA /* Special care for Ultra sockets */ if ((sk->sk_type == SOCK_DGRAM) && @@ -2020,7 +2027,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, err = -EINVAL; goto out; } - irias_insert_object(ias_obj); + + /* Only insert newly allocated objects */ + if (free_ias) + irias_insert_object(ias_obj); + kfree(ias_opt); break; case IRLMP_IAS_DEL: diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 00a8cc572a22..1f930032253a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -286,7 +286,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, goto out_unlock; } - ieee80211_key_free(key, true); + ieee80211_key_free(key, sdata->vif.type == NL80211_IFTYPE_STATION); ret = 0; out_unlock: diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 4a72c0d1e56f..91a4e606edcd 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -647,11 +647,15 @@ int ieee80211_key_link(struct ieee80211_key *key, { struct ieee80211_local *local = sdata->local; struct ieee80211_key *old_key; - int idx, ret; - bool pairwise; - - pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; - idx = key->conf.keyidx; + int idx = key->conf.keyidx; + bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; + /* + * We want to delay tailroom updates only for station - in that + * case it helps roaming speed, but in other cases it hurts and + * can cause warnings to appear. + */ + bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; + int ret; mutex_lock(&sdata->local->key_mtx); @@ -679,14 +683,14 @@ int ieee80211_key_link(struct ieee80211_key *key, increment_tailroom_need_count(sdata); ieee80211_key_replace(sdata, sta, pairwise, old_key, key); - ieee80211_key_destroy(old_key, true); + ieee80211_key_destroy(old_key, delay_tailroom); ieee80211_debugfs_key_add(key); if (!local->wowlan) { ret = ieee80211_key_enable_hw_accel(key); if (ret) - ieee80211_key_free(key, true); + ieee80211_key_free(key, delay_tailroom); } else { ret = 0; } @@ -874,7 +878,8 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, ieee80211_key_replace(key->sdata, key->sta, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key, NULL); - __ieee80211_key_destroy(key, true); + __ieee80211_key_destroy(key, key->sdata->vif.type == + NL80211_IFTYPE_STATION); } for (i = 0; i < NUM_DEFAULT_KEYS; i++) { @@ -884,7 +889,8 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, ieee80211_key_replace(key->sdata, key->sta, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key, NULL); - __ieee80211_key_destroy(key, true); + __ieee80211_key_destroy(key, key->sdata->vif.type == + NL80211_IFTYPE_STATION); } mutex_unlock(&local->key_mtx); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index dd1649caa2b2..ac212542a217 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1809,13 +1809,20 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { /* the destination server is not available */ - if (sysctl_expire_nodest_conn(ipvs)) { + __u32 flags = cp->flags; + + /* when timer already started, silently drop the packet.*/ + if (timer_pending(&cp->timer)) + __ip_vs_conn_put(cp); + else + ip_vs_conn_put(cp); + + if (sysctl_expire_nodest_conn(ipvs) && + !(flags & IP_VS_CONN_F_ONE_PACKET)) { /* try to expire the connection immediately */ ip_vs_conn_expire_now(cp); } - /* don't restart its timer, and silently - drop the packet. */ - __ip_vs_conn_put(cp); + return NF_DROP; } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 1f3c305df45d..b6e72af15237 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -876,7 +876,7 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len, if (copy_from_user(&compat_tmp, user, sizeof(compat_tmp)) != 0) return ERR_PTR(-EFAULT); - strlcpy(info->name, compat_tmp.name, sizeof(info->name)); + memcpy(info->name, compat_tmp.name, sizeof(info->name) - 1); info->num_counters = compat_tmp.num_counters; user += sizeof(compat_tmp); } else @@ -889,9 +889,9 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len, if (copy_from_user(info, user, sizeof(*info)) != 0) return ERR_PTR(-EFAULT); - info->name[sizeof(info->name) - 1] = '\0'; user += sizeof(*info); } + info->name[sizeof(info->name) - 1] = '\0'; size = sizeof(struct xt_counters); size *= info->num_counters; diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 45d4b2f22f62..aff2a1b46f7f 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -501,6 +501,9 @@ static void hhf_destroy(struct Qdisc *sch) hhf_free(q->hhf_valid_bits[i]); } + if (!q->hh_flows) + return; + for (i = 0; i < HH_FLOWS_CNT; i++) { struct hh_flow_state *flow, *next; struct list_head *head = &q->hh_flows[i]; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 87b02ed3d5f2..daa01d5604c2 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1025,6 +1025,9 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) int err; int i; + qdisc_watchdog_init(&q->watchdog, sch); + INIT_WORK(&q->work, htb_work_func); + if (!opt) return -EINVAL; @@ -1045,8 +1048,6 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) for (i = 0; i < TC_HTB_NUMPRIO; i++) INIT_LIST_HEAD(q->drops + i); - qdisc_watchdog_init(&q->watchdog, sch); - INIT_WORK(&q->work, htb_work_func); __skb_queue_head_init(&q->direct_queue); if (tb[TCA_HTB_DIRECT_QLEN]) diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index bcdd54bb101c..cef36ad691dd 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -254,7 +254,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) static int multiq_init(struct Qdisc *sch, struct nlattr *opt) { struct multiq_sched_data *q = qdisc_priv(sch); - int i, err; + int i; q->queues = NULL; @@ -269,12 +269,7 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt) for (i = 0; i < q->max_bands; i++) q->queues[i] = &noop_qdisc; - err = multiq_tune(sch, opt); - - if (err) - kfree(q->queues); - - return err; + return multiq_tune(sch, opt); } static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index b7c29d5b6f04..743ff23885da 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -943,11 +943,11 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt) struct netem_sched_data *q = qdisc_priv(sch); int ret; + qdisc_watchdog_init(&q->watchdog, sch); + if (!opt) return -EINVAL; - qdisc_watchdog_init(&q->watchdog, sch); - q->loss_model = CLG_RANDOM; ret = netem_change(sch, opt); if (ret) diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index c2fbde742f37..a06c9d6bfc9c 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -432,12 +432,13 @@ static int tbf_init(struct Qdisc *sch, struct nlattr *opt) { struct tbf_sched_data *q = qdisc_priv(sch); + qdisc_watchdog_init(&q->watchdog, sch); + q->qdisc = &noop_qdisc; + if (opt == NULL) return -EINVAL; q->t_c = ktime_get_ns(); - qdisc_watchdog_init(&q->watchdog, sch); - q->qdisc = &noop_qdisc; return tbf_change(sch, opt); } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 4615138b104f..e098ca928538 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1846,7 +1846,10 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, /* Try to instantiate a bundle */ err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family); if (err <= 0) { - if (err != 0 && err != -EAGAIN) + if (err == 0) + return NULL; + + if (err != -EAGAIN) XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); return ERR_PTR(err); } diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 0924291ef059..52aa80135426 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -373,3 +373,6 @@ endif endef # ############################################################################### + +# delete partially updated (i.e. corrupted) files on error +.DELETE_ON_ERROR: diff --git a/scripts/depmod.sh b/scripts/depmod.sh index ea1e96921e3b..baedaef53ca0 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -15,9 +15,9 @@ if ! test -r System.map ; then fi if [ -z $(command -v $DEPMOD) ]; then - echo "'make modules_install' requires $DEPMOD. Please install it." >&2 + echo "Warning: 'make modules_install' requires $DEPMOD. Please install it." >&2 echo "This is probably in the kmod package." >&2 - exit 1 + exit 0 fi # older versions of depmod don't support -P <symbol-prefix> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index bd5151915e5a..064fbfbbb22c 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -649,7 +649,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) break; if (symname[0] == '.') { - char *munged = strdup(symname); + char *munged = NOFAIL(strdup(symname)); munged[0] = '_'; munged[1] = toupper(munged[1]); symname = munged; @@ -1311,7 +1311,7 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, static char *sec2annotation(const char *s) { if (match(s, init_exit_sections)) { - char *p = malloc(20); + char *p = NOFAIL(malloc(20)); char *r = p; *p++ = '_'; @@ -1331,7 +1331,7 @@ static char *sec2annotation(const char *s) strcat(p, " "); return r; } else { - return strdup(""); + return NOFAIL(strdup("")); } } @@ -2032,7 +2032,7 @@ void buf_write(struct buffer *buf, const char *s, int len) { if (buf->size - buf->pos < len) { buf->size += len + SZ; - buf->p = realloc(buf->p, buf->size); + buf->p = NOFAIL(realloc(buf->p, buf->size)); } strncpy(buf->p + buf->pos, s, len); buf->pos += len; diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e60c79de13e1..52f3c550abcc 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -348,27 +348,26 @@ static struct avc_xperms_decision_node struct avc_xperms_decision_node *xpd_node; struct extended_perms_decision *xpd; - xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, GFP_NOWAIT); if (!xpd_node) return NULL; xpd = &xpd_node->xpd; if (which & XPERMS_ALLOWED) { xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + GFP_NOWAIT); if (!xpd->allowed) goto error; } if (which & XPERMS_AUDITALLOW) { xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + GFP_NOWAIT); if (!xpd->auditallow) goto error; } if (which & XPERMS_DONTAUDIT) { xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + GFP_NOWAIT); if (!xpd->dontaudit) goto error; } @@ -396,8 +395,7 @@ static struct avc_xperms_node *avc_xperms_alloc(void) { struct avc_xperms_node *xp_node; - xp_node = kmem_cache_zalloc(avc_xperms_cachep, - GFP_ATOMIC|__GFP_NOMEMALLOC); + xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_NOWAIT); if (!xp_node) return xp_node; INIT_LIST_HEAD(&xp_node->xpd_head); @@ -550,7 +548,7 @@ static struct avc_node *avc_alloc_node(void) { struct avc_node *node; - node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC); + node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT); if (!node) goto out; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 711084a5a029..ddf1cf3c6a45 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -652,27 +652,33 @@ EXPORT_SYMBOL(snd_interval_refine); static int snd_interval_refine_first(struct snd_interval *i) { + const unsigned int last_max = i->max; + if (snd_BUG_ON(snd_interval_empty(i))) return -EINVAL; if (snd_interval_single(i)) return 0; i->max = i->min; - i->openmax = i->openmin; - if (i->openmax) + if (i->openmin) i->max++; + /* only exclude max value if also excluded before refine */ + i->openmax = (i->openmax && i->max >= last_max); return 1; } static int snd_interval_refine_last(struct snd_interval *i) { + const unsigned int last_min = i->min; + if (snd_BUG_ON(snd_interval_empty(i))) return -EINVAL; if (snd_interval_single(i)) return 0; i->min = i->max; - i->openmin = i->openmax; - if (i->openmin) + if (i->openmax) i->min--; + /* only exclude min value if also excluded before refine */ + i->openmin = (i->openmin && i->min <= last_min); return 1; } diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index a31ea6c22d19..2d7379dec1f0 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -82,10 +82,10 @@ static void set_default_audio_parameters(struct snd_msnd *chip) { - chip->play_sample_size = DEFSAMPLESIZE; + chip->play_sample_size = snd_pcm_format_width(DEFSAMPLESIZE); chip->play_sample_rate = DEFSAMPLERATE; chip->play_channels = DEFCHANNELS; - chip->capture_sample_size = DEFSAMPLESIZE; + chip->capture_sample_size = snd_pcm_format_width(DEFSAMPLESIZE); chip->capture_sample_rate = DEFSAMPLERATE; chip->capture_channels = DEFCHANNELS; } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3324f98c35f6..f6d4a1046e54 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4019,7 +4019,8 @@ void snd_hda_bus_reset_codecs(struct hda_bus *bus) list_for_each_codec(codec, bus) { /* FIXME: maybe a better way needed for forced reset */ - cancel_delayed_work_sync(&codec->jackpoll_work); + if (current_work() != &codec->jackpoll_work.work) + cancel_delayed_work_sync(&codec->jackpoll_work); #ifdef CONFIG_PM if (hda_codec_is_power_on(codec)) { hda_call_codec_suspend(codec); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index a18aecb49935..2b770d3f05d4 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2431,6 +2431,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, WM8994_OPCLK_ENA, 0); } + break; default: return -EINVAL; diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index e4f6df077d98..0c672fd89652 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -76,6 +76,7 @@ struct swr_port { enum { WSA881X_DEV_DOWN, WSA881X_DEV_UP, + WSA881X_DEV_READY, }; /* @@ -99,6 +100,7 @@ struct wsa881x_priv { int version; struct mutex bg_lock; struct mutex res_lock; + struct mutex temp_lock; struct snd_info_entry *entry; struct snd_info_entry *version_entry; int state; @@ -464,6 +466,17 @@ static const struct file_operations codec_debug_ops = { .read = codec_debug_read, }; +static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x) +{ + mutex_lock(&wsa881x->res_lock); + if (wsa881x->state != WSA881X_DEV_READY) { + regcache_mark_dirty(wsa881x->regmap); + regcache_sync(wsa881x->regmap); + wsa881x->state = WSA881X_DEV_READY; + } + mutex_unlock(&wsa881x->res_lock); +} + static const struct reg_sequence wsa881x_pre_pmu_pa[] = { {WSA881X_SPKR_DRV_GAIN, 0x41, 0}, {WSA881X_SPKR_MISC_CTL1, 0x01, 0}, @@ -790,7 +803,9 @@ static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + mutex_lock(&wsa881x->temp_lock); wsa881x_resource_acquire(codec, ENABLE); + mutex_unlock(&wsa881x->temp_lock); wsa881x_boost_ctrl(codec, ENABLE); break; case SND_SOC_DAPM_POST_PMD: @@ -798,7 +813,9 @@ static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w, wsa881x->swr_slave->dev_num, false); wsa881x_boost_ctrl(codec, DISABLE); + mutex_lock(&wsa881x->temp_lock); wsa881x_resource_acquire(codec, DISABLE); + mutex_unlock(&wsa881x->temp_lock); break; } return 0; @@ -1042,13 +1059,8 @@ static int32_t wsa881x_temp_reg_read(struct snd_soc_codec *codec, return -EINVAL; } } - mutex_lock(&wsa881x->res_lock); - if (!wsa881x->clk_cnt) { - regcache_mark_dirty(wsa881x->regmap); - regcache_sync(wsa881x->regmap); - } - mutex_unlock(&wsa881x->res_lock); - + wsa881x_regcache_sync(wsa881x); + mutex_lock(&wsa881x->temp_lock); wsa881x_resource_acquire(codec, ENABLE); snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x00); @@ -1061,6 +1073,7 @@ static int32_t wsa881x_temp_reg_read(struct snd_soc_codec *codec, wsa_temp_reg->d2_lsb = snd_soc_read(codec, WSA881X_OTP_REG_4); wsa881x_resource_acquire(codec, DISABLE); + mutex_unlock(&wsa881x->temp_lock); return 0; } @@ -1076,7 +1089,6 @@ static int wsa881x_probe(struct snd_soc_codec *codec) dev = wsa881x->swr_slave; wsa881x->codec = codec; mutex_init(&wsa881x->bg_lock); - mutex_init(&wsa881x->res_lock); wsa881x_init(codec); snprintf(wsa881x->tz_pdata.name, sizeof(wsa881x->tz_pdata.name), "%s.%x", "wsatz", (u8)dev->addr); @@ -1098,7 +1110,6 @@ static int wsa881x_remove(struct snd_soc_codec *codec) if (wsa881x->tz_pdata.tz_dev) wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev); mutex_destroy(&wsa881x->bg_lock); - mutex_destroy(&wsa881x->res_lock); return 0; } @@ -1224,6 +1235,8 @@ static int wsa881x_swr_probe(struct swr_device *pdev) if (wsa881x->wsa_rst_np) pin_state_current = msm_cdc_pinctrl_get_state( wsa881x->wsa_rst_np); + mutex_init(&wsa881x->res_lock); + mutex_init(&wsa881x->temp_lock); wsa881x_gpio_ctrl(wsa881x, true); wsa881x->state = WSA881X_DEV_UP; @@ -1303,6 +1316,8 @@ static int wsa881x_swr_remove(struct swr_device *pdev) return -EINVAL; } debugfs_remove_recursive(debugfs_wsa881x_dent); + mutex_destroy(&wsa881x->res_lock); + mutex_destroy(&wsa881x->temp_lock); snd_soc_unregister_codec(&pdev->dev); if (wsa881x->pd_gpio) gpio_free(wsa881x->pd_gpio); @@ -1361,6 +1376,11 @@ static int wsa881x_swr_reset(struct swr_device *pdev) dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__); return -EINVAL; } + if (wsa881x->state == WSA881X_DEV_READY) { + dev_dbg(&pdev->dev, "%s: device already active\n", __func__); + return 0; + } + wsa881x->bg_cnt = 0; wsa881x->clk_cnt = 0; while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) { @@ -1368,8 +1388,7 @@ static int wsa881x_swr_reset(struct swr_device *pdev) usleep_range(1000, 1100); } pdev->dev_num = devnum; - regcache_mark_dirty(wsa881x->regmap); - regcache_sync(wsa881x->regmap); + wsa881x_regcache_sync(wsa881x); return 0; } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 69bf5cf1e91e..15cbe2565703 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2875,7 +2875,8 @@ YAMAHA_DEVICE(0x7010, "UB99"), */ #define AU0828_DEVICE(vid, pid, vname, pname) { \ - USB_DEVICE_VENDOR_SPEC(vid, pid), \ + .idVendor = vid, \ + .idProduct = pid, \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ USB_DEVICE_ID_MATCH_INT_SUBCLASS, \ diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 60a94b3e532e..177480066816 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -286,7 +286,7 @@ static int kvp_key_delete(int pool, const __u8 *key, int key_size) * Found a match; just move the remaining * entries up. */ - if (i == num_records) { + if (i == (num_records - 1)) { kvp_file_info[pool].num_records--; kvp_update_file(pool); return 0; diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index bd630c222e65..9a53f6e9ef43 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -58,9 +58,13 @@ static int check_return_reg(int ra_regno, Dwarf_Frame *frame) } /* - * Check if return address is on the stack. + * Check if return address is on the stack. If return address + * is in a register (typically R0), it is yet to be saved on + * the stack. */ - if (nops != 0 || ops != NULL) + if ((nops != 0 || ops != NULL) && + !(nops == 1 && ops[0].atom == DW_OP_regx && + ops[0].number2 == 0 && ops[0].offset == 0)) return 0; /* @@ -246,7 +250,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) if (!chain || chain->nr < 3) return skip_slot; - ip = chain->ips[2]; + ip = chain->ips[1]; thread__find_addr_location(thread, PERF_RECORD_MISC_USER, MAP__FUNCTION, ip, &al); diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 90129accffbe..4341ed267d4e 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -29,7 +29,9 @@ static inline unsigned long long rdclock(void) return ts.tv_sec * 1000000000ULL + ts.tv_nsec; } +#ifndef MAX_NR_CPUS #define MAX_NR_CPUS 1024 +#endif extern const char *input_name; extern bool perf_host, perf_guest; diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index f45cee80c58b..af2b1e66e35e 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c @@ -85,13 +85,13 @@ wait: return status; } -static void alarm_handler(int signum) +static void sig_handler(int signum) { - /* Jut wake us up from waitpid */ + /* Just wake us up from waitpid */ } -static struct sigaction alarm_action = { - .sa_handler = alarm_handler, +static struct sigaction sig_action = { + .sa_handler = sig_handler, }; int test_harness(int (test_function)(void), char *name) @@ -101,8 +101,14 @@ int test_harness(int (test_function)(void), char *name) test_start(name); test_set_git_version(GIT_VERSION); - if (sigaction(SIGALRM, &alarm_action, NULL)) { - perror("sigaction"); + if (sigaction(SIGINT, &sig_action, NULL)) { + perror("sigaction (sigint)"); + test_error(name); + return 1; + } + + if (sigaction(SIGALRM, &sig_action, NULL)) { + perror("sigaction (sigalrm)"); test_error(name); return 1; } diff --git a/tools/testing/selftests/timers/raw_skew.c b/tools/testing/selftests/timers/raw_skew.c index 30906bfd9c1b..0ab937a17ebb 100644 --- a/tools/testing/selftests/timers/raw_skew.c +++ b/tools/testing/selftests/timers/raw_skew.c @@ -146,6 +146,11 @@ int main(int argv, char **argc) printf(" %lld.%i(act)", ppm/1000, abs((int)(ppm%1000))); if (llabs(eppm - ppm) > 1000) { + if (tx1.offset || tx2.offset || + tx1.freq != tx2.freq || tx1.tick != tx2.tick) { + printf(" [SKIP]\n"); + return ksft_exit_skip("The clock was adjusted externally. Shutdown NTPd or other time sync daemons\n"); + } printf(" [FAILED]\n"); return ksft_exit_fail(); } |
