diff options
129 files changed, 3105 insertions, 895 deletions
diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 3db9ac9f0bcb..beefecad0ab0 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -6,6 +6,13 @@ ifeq ($(KERNEL_TARGET),) INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel endif +TARGET_KERNEL_MAKE_ENV := $(strip $(TARGET_KERNEL_MAKE_ENV)) +ifeq ($(TARGET_KERNEL_MAKE_ENV),) +KERNEL_MAKE_ENV := +else +KERNEL_MAKE_ENV := $(TARGET_KERNEL_MAKE_ENV) +endif + TARGET_KERNEL_ARCH := $(strip $(TARGET_KERNEL_ARCH)) ifeq ($(TARGET_KERNEL_ARCH),) KERNEL_ARCH := arm @@ -91,8 +98,8 @@ TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb endif KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr -KERNEL_MODULES_INSTALL := system -KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules +KERNEL_MODULES_INSTALL ?= system +KERNEL_MODULES_OUT ?= $(PRODUCT_OUT)/$(KERNEL_MODULES_INSTALL)/lib/modules TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL) @@ -124,43 +131,43 @@ $(KERNEL_OUT): mkdir -p $(KERNEL_OUT) $(KERNEL_CONFIG): $(KERNEL_OUT) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(hide) echo "Building kernel..." $(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install $(mv-modules) $(clean-module-folder) $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi $(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \ echo "Used a different defconfig for header generation"; \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG) env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig cp $(KERNEL_OUT)/defconfig $(TARGET_KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG) endif diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index a50e0c2b2c35..fc019bda50a7 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -79,8 +79,12 @@ Optional Properties: PCIe port PHY. Should be specified in groups (offset, value, delay). - qcom,use-19p2mhz-aux-clk: The frequency of PCIe AUX clock is 19.2MHz. - - qcom,ep-wakeirq: The endpoint will issue wake signal when it is up, and the - root complex has the capability to enumerate the endpoint for this case. + - qcom,boot-option: Bits that alter PCIe bus driver boot sequence. + Below details what happens when each bit is set + BIT(0): PCIe bus driver will not start enumeration during its probe. + Clients will control when PCIe bus driver should do enumeration. + BIT(1): PCIe bus driver will not start enumeration if it receives a WAKE + interrupt. - qcom,msi-gicm-addr: MSI address for GICv2m. - qcom,msi-gicm-base: MSI IRQ base for GICv2m. - qcom,ext-ref-clk: The reference clock is external. @@ -263,7 +267,7 @@ Example: qcom,aux-clk-sync; qcom,n-fts = <0x50>; qcom,pcie-phy-ver = <1>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; qcom,msi-gicm-addr = <0xf9040040>; qcom,msi-gicm-base = <0x160>; qcom,ext-ref-clk; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt index 9638888ebc9e..addb0a6869ac 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt @@ -154,6 +154,20 @@ First Level Node - FG Gen3 device asleep and the battery is discharging. This option requires qcom,fg-esr-timer-awake to be defined. +- qcom,fg-esr-pulse-thresh-ma + Usage: optional + Value type: <u32> + Definition: ESR pulse qualification threshold in mA. If this is not + specified, a default value of 110 mA will be configured. + Allowed values are from 1 to 997. + +- qcom,fg-esr-meas-curr-ma + Usage: optional + Value type: <u32> + Definition: ESR measurement current in mA. If this is not specified, + a default value of 120 mA will be configured. Allowed + values are 60, 120, 180 and 240. + - qcom,cycle-counter-en Usage: optional Value type: <empty> diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt index 92ef23c3a290..5529e30811fb 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt @@ -22,7 +22,8 @@ Charger specific properties: Definition: String which indicates the charging mode. Can be one of the following: Standalone/Parallel Master - "qcom,smb138x-charger" - Parallel Slave - "qcom,smb138x-parallel-slave" + smb138x Parallel Slave - "qcom,smb138x-parallel-slave" + smb1355 Parallel Slave - "qcom,smb1355-parallel-slave", - qcom,pmic-revid Usage: required @@ -35,7 +36,8 @@ Charger specific properties: Usage: optional Value type: <u32> Definition: Specifies parallel charging mode. If not specified, MID-MID - option is selected by default. + option is selected by default. Note that smb1355 can only + run in MID-MID configuration. - qcom,suspend-input Usage: optional @@ -125,7 +127,7 @@ Example ======= smb138x_charger: qcom,smb138x-charger { - compatible = "qcom,qpnp-smb138x-charger"; + compatible = "qcom,smb138x-charger"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 74aefe4e616d..351fdc160079 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -102,6 +102,22 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \ apq8096-v3-pmi8996-mdm9x55-slimbus-mtp.dtb \ apq8096-v3-pmi8996-dragonboard.dtb +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +dtbo-$(CONFIG_ARCH_MSM8998) += \ + msm8998-cdp-overlay.dtbo \ + msm8998-mtp-overlay.dtbo \ + msm8998-v2-cdp-overlay.dtbo \ + msm8998-v2-mtp-overlay.dtbo \ + msm8998-v2.1-cdp-overlay.dtbo \ + msm8998-v2.1-mtp-overlay.dtbo + +msm8998-cdp-overlay.dtbo-base := msm8998.dtb +msm8998-mtp-overlay.dtbo-base := msm8998.dtb +msm8998-v2-cdp-overlay.dtbo-base := msm8998-v2.dtb +msm8998-v2-mtp-overlay.dtbo-base := msm8998-v2.dtb +msm8998-v2.1-cdp-overlay.dtbo-base := msm8998-v2.1.dtb +msm8998-v2.1-mtp-overlay.dtbo-base := msm8998-v2.1.dtb +else dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ msm8998-rumi.dtb \ msm8998-cdp.dtb \ @@ -134,6 +150,7 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ msm8998-v2.1-interposer-sdm660-cdp.dtb \ msm8998-v2.1-interposer-sdm660-mtp.dtb \ msm8998-v2.1-interposer-sdm660-qrd.dtb +endif dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb @@ -218,6 +235,7 @@ dtb-$(CONFIG_ARCH_SDM630) += sdm630-rumi.dtb \ ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) +always += $(dtbo-y) subdir-y := $(dts-dirs) else targets += dtbs @@ -228,4 +246,4 @@ $(obj)/../%.dtb: $(src)/%.dts FORCE dtbs: $(addprefix $(obj)/../,$(dtb-y)) endif -clean-files := *.dtb +clean-files := *.dtbo *.dtb diff --git a/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi index 8757dad98b3e..49ae94e7a975 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi @@ -20,11 +20,11 @@ qcom,mdss-dsi-stream = <0>; qcom,mdss-dsi-panel-width = <1080>; qcom,mdss-dsi-panel-height = <1920>; - qcom,mdss-dsi-h-front-porch = <32>; - qcom,mdss-dsi-h-back-porch = <40>; - qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-back-porch = <12>; qcom,mdss-dsi-v-front-porch = <8>; qcom,mdss-dsi-v-pulse-width = <4>; qcom,mdss-dsi-h-left-border = <0>; @@ -104,6 +104,8 @@ qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; qcom,mdss-dsi-wr-mem-start = <0x2c>; qcom,mdss-dsi-wr-mem-continue = <0x3c>; qcom,mdss-dsi-te-pin-select = <1>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi new file mode 100644 index 000000000000..143b0152dcf4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi @@ -0,0 +1,68 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_sharp_split_link_wuxga_video: + qcom,mdss_dsi_sharp_split_link_wuxga_video { + qcom,mdss-dsi-panel-name = + "SHARP split DSI video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <600>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <54>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <6>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0x654321>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00]; + qcom,mdss-dsi-pre-off-command = [05 01 00 00 02 00 02 28 00 + 05 01 00 00 a0 00 02 10 00]; + qcom,mdss-dsi-post-panel-on-command = + [05 01 00 00 a0 00 02 29 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = + [00 24 07 08 0e 14 07 09 07 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <50>; + qcom,mdss-dsi-bl-pmic-bank-select = <2>; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 5>, <1 120>; + qcom,mdss-pan-physical-width-dimension = <83>; + qcom,mdss-pan-physical-height-dimension = <133>; + qcom,mdss-dsi-tx-eot-append; + qcom,split-link-enabled = <1>; + qcom,sublinks-count = <2>; + qcom,lanes-per-sublink = <2>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 07bd9ea842f0..5c0010d26a8a 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -287,6 +287,18 @@ qcom,vadc-thermal-node; }; + chan@4f { + label = "pa_therm0"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + chan@1d { label = "drax_temp"; reg = <0x1d>; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index 7f386957d555..fdc04b9726b4 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -330,9 +330,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pm660l_torch0: qcom,torch_0 { @@ -369,9 +366,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pm660l_switch0: qcom,led_switch_0 { @@ -386,6 +380,9 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 0cf67dd938e6..2d2b628ca815 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -712,9 +712,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pmi8998_torch0: qcom,torch_0 { @@ -751,9 +748,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pmi8998_switch0: qcom,led_switch_0 { @@ -768,6 +762,9 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index 97036ae144ae..7fffe81c7614 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -974,14 +974,14 @@ }; &pcie1 { - /delete-property/ qcom,ep-wakeirq; + /delete-property/ qcom,boot-option; }; &pcie2 { perst-gpio = <&tlmm 90 0>; wake-gpio = <&tlmm 54 0>; - /delete-property/ qcom,ep-wakeirq; + /delete-property/ qcom,boot-option; }; &wsa881x_211 { diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 7c0f8e3c331f..c73a2ff23369 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -1371,7 +1371,7 @@ iommus = <&anoc0_smmu>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; linux,pci-domain = <0>; @@ -1524,7 +1524,7 @@ iommus = <&anoc0_smmu>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; qcom,ep-latency = <10>; @@ -1677,7 +1677,7 @@ iommus = <&anoc0_smmu>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; qcom,ep-latency = <10>; diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts new file mode 100644 index 000000000000..5fe0d0176618 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#include "msm8998-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v1 CDP"; + compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp"; + qcom,msm-id = <292 0x0>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi index 2b925250c5c0..9f57fa5127d7 100644 --- a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi @@ -10,9 +10,8 @@ * GNU General Public License for more details. */ -#include "msm8998-pinctrl.dtsi" #include "msm8998-camera-sensor-cdp.dtsi" -/ { +&vendor { bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; qca,bt-vdd-io-supply = <&pm8998_s3>; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi index cfb71e3b1cb3..4a47942ce5dd 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1590,7 +1590,7 @@ qcom,ep-latency = <10>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; linux,pci-domain = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts new file mode 100644 index 000000000000..8525d781aae2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#include "msm8998-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v1 MTP"; + compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp"; + qcom,msm-id = <292 0x0>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi index f7dcfc7c149f..859e77679e44 100644 --- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi @@ -11,9 +11,8 @@ */ #include <dt-bindings/interrupt-controller/irq.h> -#include "msm8998-pinctrl.dtsi" #include "msm8998-camera-sensor-mtp.dtsi" -/ { +&vendor { bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; qca,bt-vdd-io-supply = <&pm8998_s3>; @@ -586,7 +585,7 @@ }; }; -/{ +&vendor { mtp_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-itech-3000mah.dtsi" diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index d2e18db982ef..220bad31d7f8 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -1960,16 +1960,28 @@ led_enable: led_enable { mux { pins = "gpio21"; - drive_strength = <16>; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive_strength = <2>; output-high; + bias-disable; }; }; led_disable: led_disable { mux { pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; drive_strength = <2>; output-low; + bias-disable; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi index bc87b375ff50..97c4c5b1d455 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi @@ -289,7 +289,7 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; -/{ +&vendor { qrd_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi" diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi index aa95872da385..0d0c66d7f26e 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi @@ -219,7 +219,7 @@ }; }; -/{ +&vendor { qrd_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi" diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi index 1c2db6833bde..a3eb3e5ab0d0 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi @@ -539,7 +539,7 @@ }; }; -/{ +&vendor { qrd_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-itech-3000mah.dtsi" diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts new file mode 100644 index 000000000000..c602459815b2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#include "msm8998-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v2 CDP"; + compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp"; + qcom,msm-id = <292 0x20000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts new file mode 100644 index 000000000000..660fc4d51f9f --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#include "msm8998-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v2 MTP"; + compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp"; + qcom,msm-id = <292 0x20000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts new file mode 100644 index 000000000000..47c55a045017 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#include "msm8998-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 CDP"; + compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp"; + qcom,msm-id = <292 0x20001>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts new file mode 100644 index 000000000000..54a0e98cdce7 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#include "msm8998-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MTP"; + compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp"; + qcom,msm-id = <292 0x20001>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1.dts new file mode 100644 index 000000000000..64559c71307f --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include "msm8998-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 SoC"; + compatible = "qcom,msm8998"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dts b/arch/arm/boot/dts/qcom/msm8998-v2.dts new file mode 100644 index 000000000000..f1b5af9f14c8 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include "msm8998-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v2 SoC"; + compatible = "qcom,msm8998"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998.dts b/arch/arm/boot/dts/qcom/msm8998.dts new file mode 100644 index 000000000000..b340b6de4c00 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include <dt-bindings/clock/msm-clocks-8998.h> +#include "msm8998.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8998 v1 SoC"; + compatible = "qcom,msm8998"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index d1194b3ffcec..85142c6c755e 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -275,6 +275,13 @@ soc: soc { }; + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -2678,7 +2685,7 @@ qcom,ep-latency = <10>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; linux,pci-domain = <0>; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi index 81e0c6930bf3..dfed9ec80a34 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi @@ -152,11 +152,11 @@ }; &dsi_rm67195_amoled_fhd_cmd { - qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 - 23 1e 07 08 05 03 04 a0 - 23 1e 07 08 05 03 04 a0 - 23 1e 07 08 05 03 04 a0 - 23 19 07 08 05 03 04 a0]; + 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 1a 08 09 05 03 04 a0]; qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 67e899d8ba5e..0011e1d75321 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -304,10 +304,16 @@ #size-cells = <2>; ranges; - removed_region: removed_region0@85800000 { + removed_region0: removed_region0@85800000 { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x85800000 0x0 0x3700000>; + reg = <0x0 0x85800000 0x0 0x700000>; + }; + + removed_region1: removed_region1@86000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86000000 0x0 0x2f00000>; }; modem_fw_mem: modem_fw_region@8ac00000 { @@ -1987,7 +1993,6 @@ interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; - qcom,not-wakeup; /* Needed until Full-boot-chain enabled */ status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi index fbe6d1d8cc74..33edebec2f72 100644 --- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi @@ -452,6 +452,40 @@ qcom,reset-ep-after-lpm-resume; }; + qusb_phy1: qusb@c014000 { + compatible = "qcom,qusb2phy"; + reg = <0x0c014000 0x180>, + <0x00188014 0x4>; + reg-names = "qusb_phy_base", + "ref_clk_addr"; + vdd-supply = <&pm660l_l1>; + vdda18-supply = <&pm660_l10>; + vdda33-supply = <&pm660l_l7>; + qcom,vdd-voltage-level = <1 5 7>; + qcom,qusb-phy-init-seq = <0xF8 0x80 + 0xB3 0x84 + 0x83 0x88 + 0xC0 0x8C + 0x30 0x08 + 0x79 0x0C + 0x21 0x10 + 0x14 0x9C + 0x9F 0x1C + 0x00 0x18>; + phy_type = "utmi"; + qcom,phy-clk-scheme = "cml"; + qcom,major-rev = <1>; + qcom,hold-reset; + + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_RX1_USB2_CLKREF_CLK>, + <&clock_rpmcc RPM_LN_BB_CLK1>; + clock-names = "cfg_ahb_clk", "ref_clk", "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; + }; + sdhc_1: sdhci@c0c4000 { compatible = "qcom,sdhci-msm-v5"; reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index e93190ffcf44..7d293f8d821c 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -267,11 +267,11 @@ }; &dsi_rm67195_amoled_fhd_cmd { - qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 - 23 1e 07 08 05 03 04 a0 - 23 1e 07 08 05 03 04 a0 - 23 1e 07 08 05 03 04 a0 - 23 19 07 08 05 03 04 a0]; + 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 1a 08 09 05 03 04 a0]; qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 37a88ea0dcec..efe58563a1f3 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -36,16 +36,28 @@ led_enable: led_enable { mux { pins = "gpio40"; - drive_strength = <16>; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive_strength = <2>; output-high; + bias-disable; }; }; led_disable: led_disable { mux { pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; drive_strength = <2>; output-low; + bias-disable; }; }; diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index cbfb3f4428e0..3c89828b9af2 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -210,7 +210,7 @@ if ARM64_DMA_USE_IOMMU config ARM64_DMA_IOMMU_ALIGNMENT int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers" range 4 9 - default 8 + default 9 help DMA mapping framework by default aligns all buffers to the smallest PAGE_SIZE order which is greater than or equal to the requested buffer @@ -1030,6 +1030,11 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES Space separated list of names of dtbs to append when building a concatenated Image.gz-dtb. +config BUILD_ARM64_DT_OVERLAY + bool "enable DT overlay compilation support" + depends on OF + help + This option enables support for DT overlay compilation. endmenu menu "Userspace binary formats" diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 101632379b8b..fcfa3c7dedc1 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -92,6 +92,10 @@ endif KBUILD_DTBS := dtbs +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +export DTC_FLAGS := -@ +endif + all: $(KBUILD_IMAGE) $(KBUILD_DTBS) boot := arch/arm64/boot diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 94f9a8edfd12..4f55414454fc 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -273,9 +273,15 @@ CONFIG_SMSC911X=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index b86787f5f467..dc50257f5b7a 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -273,9 +273,15 @@ CONFIG_RNDIS_IPA=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d0334e50f2f9..37b9eecf5c71 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3440,7 +3440,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) const char *failure_string; struct binder_buffer *buffer; - if (proc->tsk != current) + if (proc->tsk != current->group_leader) return -EINVAL; if ((vma->vm_end - vma->vm_start) > SZ_4M) @@ -3546,8 +3546,8 @@ static int binder_open(struct inode *nodp, struct file *filp) proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; - get_task_struct(current); - proc->tsk = current; + get_task_struct(current->group_leader); + proc->tsk = current->group_leader; INIT_LIST_HEAD(&proc->todo); init_waitqueue_head(&proc->wait); proc->default_priority = task_nice(current); diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 0c958d855f94..437077c4d44d 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -456,8 +456,13 @@ static void diag_send_feature_mask_update(uint8_t peripheral) DIAG_SET_FEATURE_MASK(F_DIAG_REQ_RSP_SUPPORT); if (driver->supports_apps_hdlc_encoding) DIAG_SET_FEATURE_MASK(F_DIAG_APPS_HDLC_ENCODE); - if (driver->supports_apps_header_untagging) - DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG); + if (driver->supports_apps_header_untagging) { + if (peripheral == PERIPHERAL_MODEM) { + DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG); + driver->peripheral_untag[peripheral] = + ENABLE_PKT_HEADER_UNTAGGING; + } + } DIAG_SET_FEATURE_MASK(F_DIAG_MASK_CENTRALIZATION); if (driver->supports_sockets) DIAG_SET_FEATURE_MASK(F_DIAG_SOCKETS_ENABLED); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 511b019e33ec..b68a47219132 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -503,6 +503,7 @@ struct diagchar_dev { int supports_separate_cmdrsp; int supports_apps_hdlc_encoding; int supports_apps_header_untagging; + int peripheral_untag[NUM_PERIPHERALS]; int supports_sockets; /* The state requested in the STM command */ int stm_state_requested[NUM_STM_PROCESSORS]; diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 532d2b149317..07c90b741fa0 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -259,11 +259,17 @@ static void pack_rsp_and_send(unsigned char *buf, int len, } if (info && info->peripheral_mask) { - for (i = 0; i <= NUM_PERIPHERALS; i++) { - if (info->peripheral_mask & (1 << i)) - break; + if (info->peripheral_mask == DIAG_CON_ALL || + (info->peripheral_mask & (1 << APPS_DATA)) || + (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) { + rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1); + } else { + for (i = 0; i <= NUM_PERIPHERALS; i++) { + if (info->peripheral_mask & (1 << i)) + break; + } + rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); } - rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); } else rsp_ctxt = driver->rsp_buf_ctxt; @@ -337,11 +343,17 @@ static void encode_rsp_and_send(unsigned char *buf, int len, } if (info && info->peripheral_mask) { - for (i = 0; i <= NUM_PERIPHERALS; i++) { - if (info->peripheral_mask & (1 << i)) - break; + if (info->peripheral_mask == DIAG_CON_ALL || + (info->peripheral_mask & (1 << APPS_DATA)) || + (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) { + rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1); + } else { + for (i = 0; i <= NUM_PERIPHERALS; i++) { + if (info->peripheral_mask & (1 << i)) + break; + } + rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); } - rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); } else rsp_ctxt = driver->rsp_buf_ctxt; @@ -1588,6 +1600,8 @@ int diagfwd_init(void) driver->supports_separate_cmdrsp = 1; driver->supports_apps_hdlc_encoding = 1; driver->supports_apps_header_untagging = 1; + for (i = 0; i < NUM_PERIPHERALS; i++) + driver->peripheral_untag[i] = 0; mutex_init(&driver->diag_hdlc_mutex); mutex_init(&driver->diag_cntl_mutex); mutex_init(&driver->mode_lock); diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index 37f3bd2626c8..2784cf71cc2b 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -468,7 +468,7 @@ static void diag_glink_connect_work_fn(struct work_struct *work) struct diag_glink_info *glink_info = container_of(work, struct diag_glink_info, connect_work); - if (!glink_info || glink_info->hdl) + if (!glink_info || !glink_info->hdl) return; atomic_set(&glink_info->opened, 1); diagfwd_channel_open(glink_info->fwd_ctxt); @@ -480,7 +480,7 @@ static void diag_glink_remote_disconnect_work_fn(struct work_struct *work) struct diag_glink_info *glink_info = container_of(work, struct diag_glink_info, remote_disconnect_work); - if (!glink_info || glink_info->hdl) + if (!glink_info || !glink_info->hdl) return; atomic_set(&glink_info->opened, 0); diagfwd_channel_close(glink_info->fwd_ctxt); diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 55d36abe4679..154f181d82f9 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -351,7 +351,8 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, } if (driver->feature[fwd_info->peripheral].encode_hdlc && - driver->feature[fwd_info->peripheral].untag_header) { + driver->feature[fwd_info->peripheral].untag_header && + driver->peripheral_untag[fwd_info->peripheral]) { mutex_lock(&driver->diagfwd_untag_mutex); temp_buf_cpd = buf; temp_buf_main = buf; @@ -990,11 +991,6 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info) if (!fwd_info->inited) return; - if (fwd_info->buf_1) - atomic_set(&fwd_info->buf_1->in_busy, 0); - if (fwd_info->buf_2) - atomic_set(&fwd_info->buf_2->in_busy, 0); - if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); @@ -1300,6 +1296,7 @@ static void diagfwd_queue_read(struct diagfwd_info *fwd_info) void diagfwd_buffers_init(struct diagfwd_info *fwd_info) { unsigned char *temp_buf; + uint8_t peripheral; if (!fwd_info) return; @@ -1311,6 +1308,9 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) } mutex_lock(&fwd_info->buf_mutex); + + peripheral = fwd_info->peripheral; + if (!fwd_info->buf_1) { fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t), GFP_KERNEL); @@ -1352,7 +1352,8 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) fwd_info->type, 2); } - if (driver->feature[fwd_info->peripheral].untag_header) { + if (driver->feature[peripheral].untag_header && + driver->peripheral_untag[peripheral]) { if (!fwd_info->buf_upd_1_a) { fwd_info->buf_upd_1_a = kzalloc(sizeof(struct diagfwd_buf_t), @@ -1426,7 +1427,8 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) } if (driver->feature[fwd_info->peripheral]. - untag_header) { + untag_header && + driver->peripheral_untag[peripheral]) { if (!fwd_info->buf_upd_1_a->data_raw) { fwd_info->buf_upd_1_a->data_raw = kzalloc(PERIPHERAL_BUF_SZ + diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c index e51cd437cf7c..eb69ed35f46d 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,41 +38,76 @@ /* Register Offsets from PLL base address */ #define PLL_ANALOG_CONTROLS_ONE 0x000 #define PLL_ANALOG_CONTROLS_TWO 0x004 +#define PLL_INT_LOOP_SETTINGS 0x008 +#define PLL_INT_LOOP_SETTINGS_TWO 0x00c #define PLL_ANALOG_CONTROLS_THREE 0x010 -#define PLL_DSM_DIVIDER 0x01c +#define PLL_ANALOG_CONTROLS_FOUR 0x014 +#define PLL_INT_LOOP_CONTROLS 0x018 +#define PLL_DSM_DIVIDER 0x01c #define PLL_FEEDBACK_DIVIDER 0x020 #define PLL_SYSTEM_MUXES 0x024 +#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028 #define PLL_CMODE 0x02c #define PLL_CALIBRATION_SETTINGS 0x030 +#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034 +#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038 +#define PLL_BAND_SEL_CAL_SETTINGS 0x03c +#define PLL_BAND_SEL_MIN 0x040 +#define PLL_BAND_SEL_MAX 0x044 +#define PLL_BAND_SEL_PFILT 0x048 +#define PLL_BAND_SEL_IFILT 0x04c +#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050 #define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054 +#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058 +#define PLL_BAND_SEL_ICODE_HIGH 0x05c +#define PLL_BAND_SEL_ICODE_LOW 0x060 #define PLL_FREQ_DETECT_SETTINGS_ONE 0x064 #define PLL_PFILT 0x07c #define PLL_IFILT 0x080 +#define PLL_GAIN 0x084 +#define PLL_ICODE_LOW 0x088 +#define PLL_ICODE_HIGH 0x08c +#define PLL_LOCKDET 0x090 #define PLL_OUTDIV 0x094 -#define PLL_CORE_OVERRIDE 0x0a4 +#define PLL_FASTLOCK_CONTROL 0x098 +#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c +#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0 +#define PLL_CORE_OVERRIDE 0x0a4 #define PLL_CORE_INPUT_OVERRIDE 0x0a8 +#define PLL_RATE_CHANGE 0x0ac +#define PLL_PLL_DIGITAL_TIMERS 0x0b0 #define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4 +#define PLL_DEC_FRAC_MUXES 0x0c8 #define PLL_DECIMAL_DIV_START_1 0x0cc #define PLL_FRAC_DIV_START_LOW_1 0x0d0 #define PLL_FRAC_DIV_START_MID_1 0x0d4 #define PLL_FRAC_DIV_START_HIGH_1 0x0d8 +#define PLL_MASH_CONTROL 0x0ec +#define PLL_SSC_MUX_CONTROL 0x108 #define PLL_SSC_STEPSIZE_LOW_1 0x10c #define PLL_SSC_STEPSIZE_HIGH_1 0x110 #define PLL_SSC_DIV_PER_LOW_1 0x114 #define PLL_SSC_DIV_PER_HIGH_1 0x118 #define PLL_SSC_DIV_ADJPER_LOW_1 0x11c #define PLL_SSC_DIV_ADJPER_HIGH_1 0x120 -#define PLL_SSC_CONTROL 0x13c -#define PLL_PLL_OUTDIV_RATE 0x140 +#define PLL_SSC_CONTROL 0x13c +#define PLL_PLL_OUTDIV_RATE 0x140 #define PLL_PLL_LOCKDET_RATE_1 0x144 #define PLL_PLL_PROP_GAIN_RATE_1 0x14c #define PLL_PLL_BAND_SET_RATE_1 0x154 #define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c #define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164 -#define PLL_PLL_LOCK_OVERRIDE 0x180 -#define PLL_PLL_LOCK_DELAY 0x184 -#define PLL_CLOCK_INVERTERS 0x18c -#define PLL_COMMON_STATUS_ONE 0x1a0 +#define PLL_FASTLOCK_EN_BAND 0x16c +#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c +#define PLL_PLL_LOCK_OVERRIDE 0x180 +#define PLL_PLL_LOCK_DELAY 0x184 +#define PLL_PLL_LOCK_MIN_DELAY 0x188 +#define PLL_CLOCK_INVERTERS 0x18c +#define PLL_SPARE_AND_JPC_OVERRIDES 0x190 +#define PLL_BIAS_CONTROL_1 0x194 +#define PLL_BIAS_CONTROL_2 0x198 +#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c +#define PLL_COMMON_STATUS_ONE 0x1a0 /* Register Offsets from PHY base address */ #define PHY_CMN_CLK_CFG0 0x010 @@ -384,6 +419,49 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_8998 *pll, MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f); } +static void dsi_pll_init_val(struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19); + MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20); + MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0); +} + static void dsi_pll_commit(struct dsi_pll_8998 *pll, struct mdss_pll_resources *rsc) { @@ -440,6 +518,8 @@ static int vco_8998_set_rate(struct clk *c, unsigned long rate) return rc; } + dsi_pll_init_val(rsc); + dsi_pll_setup_config(pll, rsc); dsi_pll_calc_dec_frac(pll, rsc); @@ -554,7 +634,6 @@ error: static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc) { - dsi_pll_disable_global_clk(rsc); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0); dsi_pll_disable_pll_bias(rsc); } @@ -573,11 +652,20 @@ static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) pr_debug("stop PLL (%d)\n", rsc->index); + /* + * To avoid any stray glitches while + * abruptly powering down the PLL + * make sure to gate the clock using + * the clock enable bit before powering + * down the PLL + **/ + dsi_pll_disable_global_clk(rsc); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0); dsi_pll_disable_sub(rsc); - if (rsc->slave) + if (rsc->slave) { + dsi_pll_disable_global_clk(rsc->slave); dsi_pll_disable_sub(rsc->slave); - + } /* flush, ensure all register writes are done*/ wmb(); rsc->pll_on = false; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 02c4f2e3155d..5b2c7e77771c 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -613,7 +613,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) /* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */ gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, - REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000); + REG_A5XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000); gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_LO, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 6cde27d51fe3..6a6d02c5444d 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -1398,7 +1398,7 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector, if (info) sde_kms_info_add_keystr(info, - "DISPLAY_TYPE", + "display type", sde_hdmi->display_type); hdmi->connector = connector; diff --git a/drivers/iio/adc/qcom-tadc.c b/drivers/iio/adc/qcom-tadc.c index 054dfcc8556a..05b1985ba378 100644 --- a/drivers/iio/adc/qcom-tadc.c +++ b/drivers/iio/adc/qcom-tadc.c @@ -228,6 +228,7 @@ struct tadc_chip { struct votable *tadc_disable_votable; struct work_struct status_change_work; struct notifier_block nb; + u8 hwtrig_conv; }; struct tadc_pt { @@ -356,6 +357,26 @@ unlock: return rc; } +static int tadc_masked_write(struct tadc_chip *chip, u16 reg, u8 mask, u8 data) +{ + int rc = 0; + + mutex_lock(&chip->write_lock); + if (tadc_is_reg_locked(chip, reg)) { + rc = regmap_write(chip->regmap, (reg & 0xFF00) | 0xD0, 0xA5); + if (rc < 0) { + pr_err("Couldn't unlock secure register rc=%d\n", rc); + goto unlock; + } + } + + rc = regmap_update_bits(chip->regmap, reg, mask, data); + +unlock: + mutex_unlock(&chip->write_lock); + return rc; +} + static int tadc_lerp(const struct tadc_pt *pts, size_t size, bool inv, s32 input, s32 *output) { @@ -880,6 +901,12 @@ static int tadc_disable_vote_callback(struct votable *votable, if (timeleft == 0) pr_err("Timed out waiting for eoc, disabling hw conversions regardless\n"); + rc = tadc_read(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), + &chip->hwtrig_conv, 1); + if (rc < 0) { + pr_err("Couldn't save hw conversions rc=%d\n", rc); + return rc; + } rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x00); if (rc < 0) { pr_err("Couldn't disable hw conversions rc=%d\n", rc); @@ -896,9 +923,10 @@ static int tadc_disable_vote_callback(struct votable *votable, pr_err("Couldn't disable direct test mode rc=%d\n", rc); return rc; } - rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x07); + rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), + chip->hwtrig_conv); if (rc < 0) { - pr_err("Couldn't enable hw conversions rc=%d\n", rc); + pr_err("Couldn't restore hw conversions rc=%d\n", rc); return rc; } } @@ -1126,16 +1154,23 @@ static int tadc_init_hw(struct tadc_chip *chip) return rc; } - /* enable all temperature hardware triggers */ - rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), - BIT(TADC_THERM1) | - BIT(TADC_THERM2) | - BIT(TADC_DIE_TEMP)); + /* enable connector and die temp hardware triggers */ + rc = tadc_masked_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), + BIT(TADC_THERM2) | BIT(TADC_DIE_TEMP), + BIT(TADC_THERM2) | BIT(TADC_DIE_TEMP)); if (rc < 0) { pr_err("Couldn't enable hardware triggers rc=%d\n", rc); return rc; } + /* save hw triggered conversion configuration */ + rc = tadc_read(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), + &chip->hwtrig_conv, 1); + if (rc < 0) { + pr_err("Couldn't save hw conversions rc=%d\n", rc); + return rc; + } + return 0; } diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 54d395d5e78d..4c28e0922c84 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -175,9 +175,7 @@ enum { struct flash_node_data { struct platform_device *pdev; struct led_classdev cdev; - struct pinctrl *pinctrl; - struct pinctrl_state *gpio_state_active; - struct pinctrl_state *gpio_state_suspend; + struct pinctrl *strobe_pinctrl; struct pinctrl_state *hw_strobe_state_active; struct pinctrl_state *hw_strobe_state_suspend; int hw_strobe_gpio; @@ -198,6 +196,9 @@ struct flash_node_data { struct flash_switch_data { struct platform_device *pdev; struct regulator *vreg; + struct pinctrl *led_en_pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; struct led_classdev cdev; int led_mask; bool regulator_on; @@ -509,7 +510,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led1n2_iclamp_low_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_low_ma, - led->fnode[0].ires_ua); + led->fnode[LED1].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base), FLASH_LED_CURRENT_MASK, val); @@ -519,7 +520,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led1n2_iclamp_mid_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_mid_ma, - led->fnode[0].ires_ua); + led->fnode[LED1].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base), FLASH_LED_CURRENT_MASK, val); @@ -529,7 +530,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led3_iclamp_low_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_low_ma, - led->fnode[3].ires_ua); + led->fnode[LED3].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED3_ICLAMP_LOW(led->base), FLASH_LED_CURRENT_MASK, val); @@ -539,7 +540,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led3_iclamp_mid_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_mid_ma, - led->fnode[3].ires_ua); + led->fnode[LED3].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED3_ICLAMP_MID(led->base), FLASH_LED_CURRENT_MASK, val); @@ -570,9 +571,9 @@ static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode, if (gpio_is_valid(fnode->hw_strobe_gpio)) { gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0); - } else if (fnode->hw_strobe_state_active && + } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active && fnode->hw_strobe_state_suspend) { - rc = pinctrl_select_state(fnode->pinctrl, + rc = pinctrl_select_state(fnode->strobe_pinctrl, on ? fnode->hw_strobe_state_active : fnode->hw_strobe_state_suspend); if (rc < 0) { @@ -948,15 +949,6 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) led->fnode[i].led_on = false; - if (led->fnode[i].pinctrl) { - rc = pinctrl_select_state(led->fnode[i].pinctrl, - led->fnode[i].gpio_state_suspend); - if (rc < 0) { - pr_err("failed to disable GPIO, rc=%d\n", rc); - return rc; - } - } - if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) { rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], led->pdata->hw_strobe_option, false); @@ -968,6 +960,17 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) } } + if (snode->led_en_pinctrl) { + pr_debug("Selecting suspend state for %s\n", snode->cdev.name); + rc = pinctrl_select_state(snode->led_en_pinctrl, + snode->gpio_state_suspend); + if (rc < 0) { + pr_err("failed to select pinctrl suspend state rc=%d\n", + rc); + return rc; + } + } + snode->enabled = false; return 0; } @@ -1038,15 +1041,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) val |= FLASH_LED_ENABLE << led->fnode[i].id; - if (led->fnode[i].pinctrl) { - rc = pinctrl_select_state(led->fnode[i].pinctrl, - led->fnode[i].gpio_state_active); - if (rc < 0) { - pr_err("failed to enable GPIO rc=%d\n", rc); - return rc; - } - } - if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) { rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], led->pdata->hw_strobe_option, true); @@ -1058,6 +1052,17 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) } } + if (snode->led_en_pinctrl) { + pr_debug("Selecting active state for %s\n", snode->cdev.name); + rc = pinctrl_select_state(snode->led_en_pinctrl, + snode->gpio_state_active); + if (rc < 0) { + pr_err("failed to select pinctrl active state rc=%d\n", + rc); + return rc; + } + } + if (led->enable == 0) { rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base), @@ -1460,6 +1465,20 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high; + rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); + if (rc < 0) { + pr_err("Unable to register led node %d\n", fnode->id); + return rc; + } + + fnode->cdev.dev->of_node = node; + fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev); + if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) { + pr_debug("No pinctrl defined for %s, err=%ld\n", + fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl)); + fnode->strobe_pinctrl = NULL; + } + if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) { if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) { fnode->hw_strobe_gpio = of_get_named_gpio(node, @@ -1469,11 +1488,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return fnode->hw_strobe_gpio; } gpio_direction_output(fnode->hw_strobe_gpio, 0); - } else { + } else if (fnode->strobe_pinctrl) { fnode->hw_strobe_gpio = -1; fnode->hw_strobe_state_active = - pinctrl_lookup_state(fnode->pinctrl, - "strobe_enable"); + pinctrl_lookup_state(fnode->strobe_pinctrl, + "strobe_enable"); if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) { pr_err("No active pin for hardware strobe, rc=%ld\n", PTR_ERR(fnode->hw_strobe_state_active)); @@ -1481,8 +1500,8 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } fnode->hw_strobe_state_suspend = - pinctrl_lookup_state(fnode->pinctrl, - "strobe_disable"); + pinctrl_lookup_state(fnode->strobe_pinctrl, + "strobe_disable"); if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) { pr_err("No suspend pin for hardware strobe, rc=%ld\n", PTR_ERR(fnode->hw_strobe_state_suspend) @@ -1492,38 +1511,6 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } } - rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); - if (rc < 0) { - pr_err("Unable to register led node %d\n", fnode->id); - return rc; - } - - fnode->cdev.dev->of_node = node; - - fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev); - if (IS_ERR_OR_NULL(fnode->pinctrl)) { - pr_debug("No pinctrl defined\n"); - fnode->pinctrl = NULL; - } else { - fnode->gpio_state_active = - pinctrl_lookup_state(fnode->pinctrl, "led_enable"); - if (IS_ERR_OR_NULL(fnode->gpio_state_active)) { - pr_err("Cannot lookup LED active state\n"); - devm_pinctrl_put(fnode->pinctrl); - fnode->pinctrl = NULL; - return PTR_ERR(fnode->gpio_state_active); - } - - fnode->gpio_state_suspend = - pinctrl_lookup_state(fnode->pinctrl, "led_disable"); - if (IS_ERR_OR_NULL(fnode->gpio_state_suspend)) { - pr_err("Cannot lookup LED disable state\n"); - devm_pinctrl_put(fnode->pinctrl); - fnode->pinctrl = NULL; - return PTR_ERR(fnode->gpio_state_suspend); - } - } - return 0; } @@ -1588,6 +1575,36 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, } snode->cdev.dev->of_node = node; + + snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev); + if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) { + pr_debug("No pinctrl defined for %s, err=%ld\n", + snode->cdev.name, PTR_ERR(snode->led_en_pinctrl)); + snode->led_en_pinctrl = NULL; + } + + if (snode->led_en_pinctrl) { + snode->gpio_state_active = + pinctrl_lookup_state(snode->led_en_pinctrl, + "led_enable"); + if (IS_ERR_OR_NULL(snode->gpio_state_active)) { + pr_err("Cannot lookup LED active state\n"); + devm_pinctrl_put(snode->led_en_pinctrl); + snode->led_en_pinctrl = NULL; + return PTR_ERR(snode->gpio_state_active); + } + + snode->gpio_state_suspend = + pinctrl_lookup_state(snode->led_en_pinctrl, + "led_disable"); + if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) { + pr_err("Cannot lookup LED disable state\n"); + devm_pinctrl_put(snode->led_en_pinctrl); + snode->led_en_pinctrl = NULL; + return PTR_ERR(snode->gpio_state_suspend); + } + } + return 0; } @@ -2094,22 +2111,24 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) if (!strcmp("flash", temp_string) || !strcmp("torch", temp_string)) { rc = qpnp_flash_led_parse_each_led_dt(led, - &led->fnode[i++], temp); + &led->fnode[i], temp); if (rc < 0) { pr_err("Unable to parse flash node %d rc=%d\n", i, rc); goto error_led_register; } + i++; } if (!strcmp("switch", temp_string)) { rc = qpnp_flash_led_parse_and_register_switch(led, - &led->snode[j++], temp); + &led->snode[j], temp); if (rc < 0) { pr_err("Unable to parse and register switch node, rc=%d\n", rc); goto error_switch_register; } + j++; } } diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index a63279715de6..a8dc1d010d62 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -766,6 +766,8 @@ static int __init msm_vidc_init(void) if (rc) { dprintk(VIDC_ERR, "Failed to register platform driver\n"); + msm_vidc_debugfs_deinit_drv(); + debugfs_remove_recursive(vidc_driver->debugfs_root); kfree(vidc_driver); vidc_driver = NULL; } @@ -776,6 +778,7 @@ static int __init msm_vidc_init(void) static void __exit msm_vidc_exit(void) { platform_driver_unregister(&msm_vidc_driver); + msm_vidc_debugfs_deinit_drv(); debugfs_remove_recursive(vidc_driver->debugfs_root); mutex_destroy(&vidc_driver->lock); kfree(vidc_driver); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 24eb8fff905b..953780e3c220 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -2587,6 +2587,12 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, int rc = 0, i = 0, fourcc = 0; struct v4l2_ext_control *ext_control; struct v4l2_control control; + u32 old_mode = 0; + bool mode_changed = false; + enum mode { + PRIMARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY, + SECONDARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY + }; if (!inst || !inst->core || !ctrl) { dprintk(VIDC_ERR, @@ -2595,19 +2601,21 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, } ext_control = ctrl->controls; - control.id = - V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; + old_mode = msm_comm_g_ctrl_for_id(inst, control.id); for (i = 0; i < ctrl->count; i++) { switch (ext_control[i].id) { case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE: control.value = ext_control[i].value; - rc = msm_comm_s_ctrl(inst, &control); if (rc) dprintk(VIDC_ERR, "%s Failed setting stream output mode : %d\n", __func__, rc); + + if (old_mode == SECONDARY && control.value == PRIMARY) + mode_changed = true; break; case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT: switch (ext_control[i].value) { @@ -2620,6 +2628,24 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, "%s Release output buffers failed\n", __func__); } + /* Update buffer reqmt for split to comb mode */ + if (mode_changed) { + fourcc = + inst->fmts[CAPTURE_PORT].fourcc; + msm_comm_set_color_format(inst, + HAL_BUFFER_OUTPUT, fourcc); + if (rc) { + dprintk(VIDC_ERR, + "%s Failed setting output color format : %d\n", + __func__, rc); + break; + } + rc = msm_comm_try_get_bufreqs(inst); + if (rc) + dprintk(VIDC_ERR, + "%s Failed to get buffer requirements : %d\n", + __func__, rc); + } break; case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC: case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC: diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 8b459e4da618..7b28e80979f2 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -902,7 +902,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "sess resp timeout can potentially crash the system\n"); msm_comm_print_debug_info(inst); - BUG_ON(inst->core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); msm_comm_kill_session(inst); rc = -EIO; } else { @@ -1748,7 +1748,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) msm_comm_print_inst_info(inst); mutex_unlock(&core->lock); - BUG_ON(core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); } void msm_comm_session_clean(struct msm_vidc_inst *inst) @@ -2543,7 +2543,7 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst) "ABORT timeout can potentially crash the system\n"); msm_comm_print_debug_info(inst); - BUG_ON(inst->core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); rc = -EBUSY; } else { rc = 0; @@ -2645,7 +2645,7 @@ int msm_comm_check_core_init(struct msm_vidc_core *core) msm_comm_print_debug_info(inst); mutex_lock(&core->lock); - BUG_ON(core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); rc = -EIO; goto exit; } else { @@ -4110,10 +4110,9 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "SESS_PROP timeout can potentially crash the system\n"); - if (inst->core->resources.debug_timeout) - msm_comm_print_debug_info(inst); + msm_comm_print_debug_info(inst); - BUG_ON(inst->core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); msm_comm_kill_session(inst); rc = -ETIMEDOUT; goto exit; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 1248a1c08103..a9b367d6fe93 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -38,6 +38,7 @@ bool msm_vidc_debug_timeout = false; #define MAX_DBG_BUF_SIZE 4096 struct debug_buffer { + struct mutex lock; char ptr[MAX_DBG_BUF_SIZE]; char *curr; u32 filled_size; @@ -64,8 +65,12 @@ static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...) { va_list args; u32 size; + + char *curr = buffer->curr; + char *end = buffer->ptr + MAX_DBG_BUF_SIZE; + va_start(args, fmt); - size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args); + size = vscnprintf(curr, end - curr, fmt, args); va_end(args); buffer->curr += size; buffer->filled_size += size; @@ -79,12 +84,15 @@ static ssize_t core_info_read(struct file *file, char __user *buf, struct hfi_device *hdev; struct hal_fw_info fw_info = { {0} }; int i = 0, rc = 0; + ssize_t len = 0; if (!core || !core->device) { dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core); return 0; } hdev = core->device; + + mutex_lock(&dbg_buf.lock); INIT_DBG_BUF(dbg_buf); write_str(&dbg_buf, "===============================\n"); write_str(&dbg_buf, "CORE %d: %pK\n", core->id, core); @@ -108,8 +116,11 @@ err_fw_info: completion_done(&core->completions[SYS_MSG_INDEX(i)]) ? "pending" : "done"); } - return simple_read_from_buffer(buf, count, ppos, + len = simple_read_from_buffer(buf, count, ppos, dbg_buf.ptr, dbg_buf.filled_size); + + mutex_unlock(&dbg_buf.lock); + return len; } static const struct file_operations core_info_fops = { @@ -147,7 +158,10 @@ static const struct file_operations ssr_fops = { struct dentry *msm_vidc_debugfs_init_drv(void) { bool ok = false; - struct dentry *dir = debugfs_create_dir("msm_vidc", NULL); + struct dentry *dir = NULL; + + mutex_init(&dbg_buf.lock); + dir = debugfs_create_dir("msm_vidc", NULL); if (IS_ERR_OR_NULL(dir)) { dir = NULL; goto failed_create_dir; @@ -216,6 +230,7 @@ struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); goto failed_create_dir; } + if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) { dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); goto failed_create_dir; @@ -269,11 +284,14 @@ static ssize_t inst_info_read(struct file *file, char __user *buf, { struct msm_vidc_inst *inst = file->private_data; int i, j; + ssize_t len = 0; if (!inst) { dprintk(VIDC_ERR, "Invalid params, inst %pK\n", inst); return 0; } + + mutex_lock(&dbg_buf.lock); INIT_DBG_BUF(dbg_buf); write_str(&dbg_buf, "===============================\n"); write_str(&dbg_buf, "INSTANCE: %pK (%s)\n", inst, @@ -331,8 +349,10 @@ static ssize_t inst_info_read(struct file *file, char __user *buf, publish_unreleased_reference(inst); - return simple_read_from_buffer(buf, count, ppos, + len = simple_read_from_buffer(buf, count, ppos, dbg_buf.ptr, dbg_buf.filled_size); + mutex_unlock(&dbg_buf.lock); + return len; } static const struct file_operations inst_info_fops = { @@ -413,3 +433,8 @@ void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, } } +void msm_vidc_debugfs_deinit_drv(void) +{ + mutex_destroy(&dbg_buf.lock); +} + diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index 39ac6273f34e..853ce4b89f2b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -126,6 +126,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, struct dentry *parent); void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, enum msm_vidc_debugfs_event e); +void msm_vidc_debugfs_deinit_drv(void); static inline void tic(struct msm_vidc_inst *i, enum profiling_points p, char *b) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index a65e22c66e30..4cc977e568ee 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1123,7 +1123,7 @@ int read_platform_resources_from_dt( res->debug_timeout = of_property_read_bool(pdev->dev.of_node, "qcom,debug-timeout"); - res->debug_timeout |= msm_vidc_debug_timeout; + msm_vidc_debug_timeout |= res->debug_timeout; of_property_read_u32(pdev->dev.of_node, "qcom,pm-qos-latency-us", &res->pm_qos_latency_us); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5ab09b4ae868..3b79f514350e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2031,7 +2031,7 @@ reinit: err = mmc_select_hs400(card); if (err) goto free_card; - } else { + } else if (!mmc_card_hs400(card)) { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) { diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c index bf6502e27bdd..015cb99d445b 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c +++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c @@ -35,6 +35,7 @@ #define MHI_NAPI_WEIGHT_VALUE 12 #define WATCHDOG_TIMEOUT (30 * HZ) #define RMNET_IPC_LOG_PAGES (100) +#define IRQ_MASKED_BIT (0) enum DBG_LVL { MSG_VERBOSE = 0x1, @@ -100,14 +101,15 @@ struct rmnet_mhi_private { u32 mhi_enabled; struct platform_device *pdev; struct net_device *dev; - atomic_t irq_masked_cntr; + unsigned long flags; + int wake_count; spinlock_t out_chan_full_lock; /* tx queue lock */ - atomic_t pending_data; struct sk_buff *frag_skb; struct work_struct alloc_work; /* lock to queue hardware and internal queue */ spinlock_t alloc_lock; void *rmnet_ipc_log; + rwlock_t pm_lock; /* state change lock */ struct debug_params debug; struct dentry *dentry; }; @@ -130,12 +132,12 @@ static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr, rmnet_mhi_ptr->frag_skb = NULL; return -ENOMEM; } - kfree_skb(rmnet_mhi_ptr->frag_skb); + dev_kfree_skb_any(rmnet_mhi_ptr->frag_skb); rmnet_mhi_ptr->frag_skb = temp_skb; memcpy(skb_put(rmnet_mhi_ptr->frag_skb, skb->len), skb->data, skb->len); - kfree_skb(skb); + dev_kfree_skb_any(skb); if (!frag) { /* Last fragmented piece was received, ship it */ netif_receive_skb(rmnet_mhi_ptr->frag_skb); @@ -196,7 +198,6 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, { u32 cur_mru = rmnet_mhi_ptr->mru; struct mhi_skb_priv *skb_priv; - unsigned long flags; int ret; struct sk_buff *skb; @@ -215,7 +216,7 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, skb_priv->dma_addr = 0; /* These steps must be in atomic context */ - spin_lock_irqsave(&rmnet_mhi_ptr->alloc_lock, flags); + spin_lock_bh(&rmnet_mhi_ptr->alloc_lock); /* It's possible by the time alloc_skb (GFP_KERNEL) * returns we already called rmnet_alloc_rx @@ -224,14 +225,22 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, */ if (unlikely(atomic_read(&rmnet_mhi_ptr->rx_pool_len) >= rmnet_mhi_ptr->rx_buffers_max)) { - spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, - flags); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); dev_kfree_skb_any(skb); return 0; } - ret = mhi_queue_xfer( - rmnet_mhi_ptr->rx_client_handle, + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "!interface is disabled\n"); + dev_kfree_skb_any(skb); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); + return -EIO; + } + + ret = mhi_queue_xfer(rmnet_mhi_ptr->rx_client_handle, skb->data, skb_priv->dma_size, MHI_EOT); @@ -239,14 +248,15 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, "mhi_queue_xfer failed, error %d", ret); - spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, - flags); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); dev_kfree_skb_any(skb); return ret; } skb_queue_tail(&rmnet_mhi_ptr->rx_buffers, skb); atomic_inc(&rmnet_mhi_ptr->rx_pool_len); - spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, flags); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); } return 0; @@ -258,13 +268,25 @@ static void rmnet_mhi_alloc_work(struct work_struct *work) struct rmnet_mhi_private, alloc_work); int ret; + /* sleep about 1 sec and retry, that should be enough time + * for system to reclaim freed memory back. + */ + const int sleep_ms = 1000; + int retry = 60; rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); - ret = rmnet_alloc_rx(rmnet_mhi_ptr, - rmnet_mhi_ptr->allocation_flags); + do { + ret = rmnet_alloc_rx(rmnet_mhi_ptr, + rmnet_mhi_ptr->allocation_flags); + /* sleep and try again */ + if (ret == -ENOMEM) { + msleep(sleep_ms); + retry--; + } + } while (ret == -ENOMEM && retry); - WARN_ON(ret == -ENOMEM); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit with status:%d retry:%d\n", + ret, retry); } static int rmnet_mhi_poll(struct napi_struct *napi, int budget) @@ -281,6 +303,12 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "interface is disabled!\n"); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + return 0; + } while (received_packets < budget) { struct mhi_result *result = mhi_poll(rmnet_mhi_ptr->rx_client_handle); @@ -338,77 +366,50 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) dev->stats.rx_bytes += result->bytes_xferd; } /* while (received_packets < budget) or any other error */ + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); /* Queue new buffers */ res = rmnet_alloc_rx(rmnet_mhi_ptr, GFP_ATOMIC); - if (res == -ENOMEM) { - rmnet_log(rmnet_mhi_ptr, - MSG_INFO, - "out of mem, queuing bg worker\n"); - rmnet_mhi_ptr->alloc_fail++; - schedule_work(&rmnet_mhi_ptr->alloc_work); - } - napi_complete(napi); + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + if (res == -ENOMEM) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "out of mem, queuing bg worker\n"); + rmnet_mhi_ptr->alloc_fail++; + schedule_work(&rmnet_mhi_ptr->alloc_work); + } + + napi_complete(napi); - /* We got a NULL descriptor back */ - if (should_reschedule == false) { - if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { - atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); + /* We got a NULL descriptor back */ + if (!should_reschedule) { + if (test_and_clear_bit(IRQ_MASKED_BIT, + &rmnet_mhi_ptr->flags)) + mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, true); + rmnet_mhi_ptr->wake_count--; + } else { + if (received_packets == budget) + rmnet_mhi_ptr->debug.rx_napi_budget_overflow++; + napi_reschedule(napi); } - } else { - if (received_packets == budget) - rmnet_mhi_ptr->debug.rx_napi_budget_overflow++; - napi_reschedule(napi); - } - rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = - min((u64)received_packets, - rmnet_mhi_ptr->debug.rx_napi_skb_burst_min); + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = + min((u64)received_packets, + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min); - rmnet_mhi_ptr->debug.rx_napi_skb_burst_max = - max((u64)received_packets, - rmnet_mhi_ptr->debug.rx_napi_skb_burst_max); + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max = + max((u64)received_packets, + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max); + } + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited, polled %d pkts\n", received_packets); return received_packets; } -void rmnet_mhi_clean_buffers(struct net_device *dev) -{ - struct rmnet_mhi_private *rmnet_mhi_ptr = - *(struct rmnet_mhi_private **)netdev_priv(dev); - - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); - /* Clean TX buffers */ - rmnet_mhi_internal_clean_unmap_buffers(dev, - &rmnet_mhi_ptr->tx_buffers, - DMA_TO_DEVICE); - - /* Clean RX buffers */ - rmnet_mhi_internal_clean_unmap_buffers(dev, - &rmnet_mhi_ptr->rx_buffers, - DMA_FROM_DEVICE); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited\n"); -} - -static int rmnet_mhi_disable_channels(struct rmnet_mhi_private *rmnet_mhi_ptr) -{ - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI TX channel\n"); - mhi_close_channel(rmnet_mhi_ptr->tx_client_handle); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI RX channel\n"); - mhi_close_channel(rmnet_mhi_ptr->rx_client_handle); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Clearing Pending TX buffers.\n"); - rmnet_mhi_clean_buffers(rmnet_mhi_ptr->dev); - rmnet_mhi_ptr->tx_client_handle = NULL; - rmnet_mhi_ptr->rx_client_handle = NULL; - - return 0; -} - static int rmnet_mhi_init_inbound(struct rmnet_mhi_private *rmnet_mhi_ptr) { int res; @@ -431,7 +432,7 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) struct net_device *dev; struct rmnet_mhi_private *rmnet_mhi_ptr; unsigned long burst_counter = 0; - unsigned long flags; + unsigned long flags, pm_flags; rmnet_mhi_ptr = result->user_data; dev = rmnet_mhi_ptr->dev; @@ -451,10 +452,10 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) break; } else { if (skb->data == result->buf_addr) { - kfree_skb(skb); + dev_kfree_skb_any(skb); break; } - kfree_skb(skb); + dev_kfree_skb_any(skb); burst_counter++; /* Update statistics */ @@ -477,10 +478,15 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max); /* In case we couldn't write again, now we can! */ - spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); - rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n"); - netif_wake_queue(dev); - spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); + read_lock_irqsave(&rmnet_mhi_ptr->pm_lock, pm_flags); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n"); + netif_wake_queue(dev); + spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, + flags); + } + read_unlock_irqrestore(&rmnet_mhi_ptr->pm_lock, pm_flags); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); } @@ -488,20 +494,27 @@ static void rmnet_mhi_rx_cb(struct mhi_result *result) { struct net_device *dev; struct rmnet_mhi_private *rmnet_mhi_ptr; + unsigned long flags; + rmnet_mhi_ptr = result->user_data; dev = rmnet_mhi_ptr->dev; rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); rmnet_mhi_ptr->debug.rx_interrupts_count++; - - if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) { - mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr); - mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); - __napi_schedule(&(rmnet_mhi_ptr->napi)); - } else { - rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + read_lock_irqsave(&rmnet_mhi_ptr->pm_lock, flags); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + if (napi_schedule_prep(&rmnet_mhi_ptr->napi)) { + if (!test_and_set_bit(IRQ_MASKED_BIT, + &rmnet_mhi_ptr->flags)) + mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); + rmnet_mhi_ptr->wake_count++; + __napi_schedule(&rmnet_mhi_ptr->napi); + } else { + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + } } + read_unlock_irqrestore(&rmnet_mhi_ptr->pm_lock, flags); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); } @@ -510,8 +523,7 @@ static int rmnet_mhi_open(struct net_device *dev) struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); - rmnet_log(rmnet_mhi_ptr, - MSG_INFO, + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Opened net dev interface for MHI chans %d and %d\n", rmnet_mhi_ptr->tx_channel, rmnet_mhi_ptr->rx_channel); @@ -527,43 +539,35 @@ static int rmnet_mhi_open(struct net_device *dev) /* Poll to check if any buffers are accumulated in the * transport buffers */ - if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) { - mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr); - mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); - __napi_schedule(&(rmnet_mhi_ptr->napi)); - } else { - rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + if (napi_schedule_prep(&rmnet_mhi_ptr->napi)) { + if (!test_and_set_bit(IRQ_MASKED_BIT, + &rmnet_mhi_ptr->flags)) { + mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); + } + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); + rmnet_mhi_ptr->wake_count++; + __napi_schedule(&rmnet_mhi_ptr->napi); + } else { + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + } } + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); return 0; } -static int rmnet_mhi_disable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) -{ - rmnet_mhi_ptr->rx_enabled = 0; - rmnet_mhi_ptr->tx_enabled = 0; - rmnet_mhi_ptr->mhi_enabled = 0; - if (rmnet_mhi_ptr->dev != 0) { - netif_stop_queue(rmnet_mhi_ptr->dev); - netif_napi_del(&(rmnet_mhi_ptr->napi)); - rmnet_mhi_disable_channels(rmnet_mhi_ptr); - unregister_netdev(rmnet_mhi_ptr->dev); - free_netdev(rmnet_mhi_ptr->dev); - rmnet_mhi_ptr->dev = 0; - } - return 0; -} - static int rmnet_mhi_disable(struct rmnet_mhi_private *rmnet_mhi_ptr) { - rmnet_mhi_ptr->mhi_enabled = 0; - rmnet_mhi_disable_iface(rmnet_mhi_ptr); napi_disable(&(rmnet_mhi_ptr->napi)); - if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { + rmnet_mhi_ptr->rx_enabled = 0; + rmnet_mhi_internal_clean_unmap_buffers(rmnet_mhi_ptr->dev, + &rmnet_mhi_ptr->rx_buffers, + DMA_FROM_DEVICE); + if (test_and_clear_bit(IRQ_MASKED_BIT, &rmnet_mhi_ptr->flags)) mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - } + return 0; } @@ -574,11 +578,9 @@ static int rmnet_mhi_stop(struct net_device *dev) netif_stop_queue(dev); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); - if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { + if (test_and_clear_bit(IRQ_MASKED_BIT, &rmnet_mhi_ptr->flags)) { mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - rmnet_log(rmnet_mhi_ptr, - MSG_ERROR, + rmnet_log(rmnet_mhi_ptr, MSG_ERROR, "IRQ was masked, unmasking...\n"); } rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); @@ -605,14 +607,23 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct mhi_skb_priv *tx_priv; - rmnet_log(rmnet_mhi_ptr, - MSG_VERBOSE, - "Entered chan %d\n", - rmnet_mhi_ptr->tx_channel); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, + "Entered chan %d\n", rmnet_mhi_ptr->tx_channel); tx_priv = (struct mhi_skb_priv *)(skb->cb); tx_priv->dma_size = skb->len; tx_priv->dma_addr = 0; + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) { + /* Only reason interface could be disabled and we get data + * is due to an SSR. We do not want to stop the queue and + * return error. instead we will flush all the uplink packets + * and return successful + */ + res = NETDEV_TX_OK; + dev_kfree_skb_any(skb); + goto mhi_xmit_exit; + } if (mhi_get_free_desc(rmnet_mhi_ptr->tx_client_handle) <= 0) { rmnet_log(rmnet_mhi_ptr, @@ -624,7 +635,8 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); - return NETDEV_TX_BUSY; + res = NETDEV_TX_BUSY; + goto mhi_xmit_exit; } res = mhi_queue_xfer(rmnet_mhi_ptr->tx_client_handle, skb->data, @@ -641,15 +653,17 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); - return NETDEV_TX_BUSY; + res = NETDEV_TX_BUSY; + goto mhi_xmit_exit; } - + res = NETDEV_TX_OK; skb_queue_tail(&(rmnet_mhi_ptr->tx_buffers), skb); dev->trans_start = jiffies; rmnet_mhi_ptr->debug.tx_queued_packets_count++; - +mhi_xmit_exit: + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); - return NETDEV_TX_OK; + return res; } static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) @@ -698,16 +712,19 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) sizeof(ext_cmd.u.if_name)); break; case RMNET_IOCTL_SET_SLEEP_STATE: + read_lock_bh(&rmnet_mhi_ptr->pm_lock); if (rmnet_mhi_ptr->mhi_enabled && rmnet_mhi_ptr->tx_client_handle != NULL) { + rmnet_mhi_ptr->wake_count += (ext_cmd.u.data) ? -1 : 1; mhi_set_lpm(rmnet_mhi_ptr->tx_client_handle, ext_cmd.u.data); } else { - rmnet_log(rmnet_mhi_ptr, - MSG_ERROR, + rmnet_log(rmnet_mhi_ptr, MSG_ERROR, "Cannot set LPM value, MHI is not up.\n"); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); return -ENODEV; } + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); break; default: rc = -EINVAL; @@ -832,9 +849,8 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) "Failed to start TX chan ret %d\n", r); goto mhi_tx_chan_start_fail; - } else { - rmnet_mhi_ptr->tx_enabled = 1; } + client_handle = rmnet_mhi_ptr->tx_client_handle; } if (rmnet_mhi_ptr->rx_client_handle != NULL) { @@ -848,8 +864,6 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) "Failed to start RX chan ret %d\n", r); goto mhi_rx_chan_start_fail; - } else { - rmnet_mhi_ptr->rx_enabled = 1; } /* Both tx & rx client handle contain same device info */ client_handle = rmnet_mhi_ptr->rx_client_handle; @@ -860,62 +874,64 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) goto net_dev_alloc_fail; } - snprintf(ifalias, - sizeof(ifalias), - "%s_%04x_%02u.%02u.%02u_%u", - rmnet_mhi_ptr->interface_name, - client_handle->dev_id, - client_handle->domain, - client_handle->bus, - client_handle->slot, - rmnet_mhi_ptr->dev_id); - - snprintf(ifname, sizeof(ifname), "%s%%d", - rmnet_mhi_ptr->interface_name); - rtnl_lock(); - rmnet_mhi_ptr->dev = - alloc_netdev(sizeof(struct rmnet_mhi_private *), - ifname, NET_NAME_PREDICTABLE, rmnet_mhi_setup); if (!rmnet_mhi_ptr->dev) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Network device allocation failed\n"); - ret = -ENOMEM; - goto net_dev_alloc_fail; + snprintf(ifalias, sizeof(ifalias), + "%s_%04x_%02u.%02u.%02u_%u", + rmnet_mhi_ptr->interface_name, + client_handle->dev_id, + client_handle->domain, + client_handle->bus, + client_handle->slot, + rmnet_mhi_ptr->dev_id); + + snprintf(ifname, sizeof(ifname), "%s%%d", + rmnet_mhi_ptr->interface_name); + + rtnl_lock(); + rmnet_mhi_ptr->dev = alloc_netdev( + sizeof(struct rmnet_mhi_private *), + ifname, NET_NAME_PREDICTABLE, rmnet_mhi_setup); + + if (!rmnet_mhi_ptr->dev) { + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, + "Network device allocation failed\n"); + ret = -ENOMEM; + goto net_dev_alloc_fail; + } + SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev); + dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias)); + rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev); + rtnl_unlock(); + *rmnet_mhi_ctxt = rmnet_mhi_ptr; + + ret = dma_set_mask(&rmnet_mhi_ptr->dev->dev, MHI_DMA_MASK); + if (ret) + rmnet_mhi_ptr->allocation_flags = GFP_KERNEL; + else + rmnet_mhi_ptr->allocation_flags = GFP_DMA; + + netif_napi_add(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->napi, + rmnet_mhi_poll, MHI_NAPI_WEIGHT_VALUE); + + ret = register_netdev(rmnet_mhi_ptr->dev); + if (ret) { + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, + "Network device registration failed\n"); + goto net_dev_reg_fail; + } } - SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev); - dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias)); - rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev); - rtnl_unlock(); - *rmnet_mhi_ctxt = rmnet_mhi_ptr; - - ret = dma_set_mask(&(rmnet_mhi_ptr->dev->dev), - MHI_DMA_MASK); - if (ret) - rmnet_mhi_ptr->allocation_flags = GFP_KERNEL; - else - rmnet_mhi_ptr->allocation_flags = GFP_DMA; + + write_lock_irq(&rmnet_mhi_ptr->pm_lock); + rmnet_mhi_ptr->mhi_enabled = 1; + write_unlock_irq(&rmnet_mhi_ptr->pm_lock); r = rmnet_mhi_init_inbound(rmnet_mhi_ptr); if (r) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Failed to init inbound ret %d\n", - r); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Failed to init inbound ret %d\n", r); } - netif_napi_add(rmnet_mhi_ptr->dev, &(rmnet_mhi_ptr->napi), - rmnet_mhi_poll, MHI_NAPI_WEIGHT_VALUE); - - rmnet_mhi_ptr->mhi_enabled = 1; - ret = register_netdev(rmnet_mhi_ptr->dev); - if (ret) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Network device registration failed\n"); - goto net_dev_reg_fail; - } napi_enable(&(rmnet_mhi_ptr->napi)); rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited.\n"); @@ -951,25 +967,47 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) switch (cb_info->cb_reason) { case MHI_CB_MHI_DISABLED: - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Got MHI_DISABLED notification. Stopping stack\n"); - if (rmnet_mhi_ptr->mhi_enabled) { - rmnet_mhi_ptr->mhi_enabled = 0; - /* Ensure MHI is disabled before other mem ops */ - wmb(); - while (atomic_read(&rmnet_mhi_ptr->pending_data)) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Waiting for channels to stop.\n"); - msleep(25); - } + case MHI_CB_MHI_SHUTDOWN: + case MHI_CB_SYS_ERROR: + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Got MHI_SYS_ERROR notification. Stopping stack\n"); + + /* Disable interface on first notification. Long + * as we set mhi_enabled = 0, we gurantee rest of + * driver will not touch any critical data. + */ + write_lock_irq(&rmnet_mhi_ptr->pm_lock); + rmnet_mhi_ptr->mhi_enabled = 0; + write_unlock_irq(&rmnet_mhi_ptr->pm_lock); + + if (cb_info->chan == rmnet_mhi_ptr->rx_channel) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Receive MHI_DISABLE notification for rx path\n"); rmnet_mhi_disable(rmnet_mhi_ptr); + } else { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Receive MHI_DISABLE notification for tx path\n"); + rmnet_mhi_ptr->tx_enabled = 0; + rmnet_mhi_internal_clean_unmap_buffers + (rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->tx_buffers, + DMA_TO_DEVICE); + } + + /* Remove all votes disabling low power mode */ + if (!rmnet_mhi_ptr->tx_enabled && !rmnet_mhi_ptr->rx_enabled) { + struct mhi_client_handle *handle = + rmnet_mhi_ptr->rx_client_handle; + + if (!handle) + handle = rmnet_mhi_ptr->tx_client_handle; + while (rmnet_mhi_ptr->wake_count) { + mhi_set_lpm(handle, true); + rmnet_mhi_ptr->wake_count--; + } } break; case MHI_CB_MHI_ENABLED: - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Got MHI_ENABLED notification. Starting stack\n"); if (cb_info->chan == rmnet_mhi_ptr->rx_channel) rmnet_mhi_ptr->rx_enabled = 1; @@ -998,16 +1036,10 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) } break; case MHI_CB_XFER: - atomic_inc(&rmnet_mhi_ptr->pending_data); - /* Flush pending data is set before any other mem operations */ - wmb(); - if (rmnet_mhi_ptr->mhi_enabled) { - if (cb_info->chan == rmnet_mhi_ptr->rx_channel) - rmnet_mhi_rx_cb(cb_info->result); - else - rmnet_mhi_tx_cb(cb_info->result); - } - atomic_dec(&rmnet_mhi_ptr->pending_data); + if (cb_info->chan == rmnet_mhi_ptr->rx_channel) + rmnet_mhi_rx_cb(cb_info->result); + else + rmnet_mhi_tx_cb(cb_info->result); break; default: break; @@ -1172,6 +1204,7 @@ static int rmnet_mhi_probe(struct platform_device *pdev) return -ENOMEM; rmnet_mhi_ptr->pdev = pdev; spin_lock_init(&rmnet_mhi_ptr->out_chan_full_lock); + rwlock_init(&rmnet_mhi_ptr->pm_lock); rc = of_property_read_u32(pdev->dev.of_node, "qcom,mhi-mru", diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 7d20f087da71..f172671cb00f 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -29,21 +29,34 @@ ath10k_snoc_service_notifier_notify(struct notifier_block *nb, service_notifier_nb); enum pd_subsys_state *state = data; struct ath10k *ar = ar_snoc->ar; + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + int ret; switch (notification) { case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service down, data: 0x%pK\n", data); - if (!state || *state != ROOT_PD_SHUTDOWN) + if (!state || *state != ROOT_PD_SHUTDOWN) { atomic_set(&ar_snoc->fw_crashed, 1); + atomic_set(&qmi_cfg->fw_ready, 0); + } ath10k_dbg(ar, ATH10K_DBG_SNOC, "PD went down %d\n", atomic_read(&ar_snoc->fw_crashed)); break; case SERVREG_NOTIF_SERVICE_STATE_UP_V01: ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service up\n"); - queue_work(ar->workqueue, &ar->restart_work); + ret = wait_event_timeout(ath10k_fw_ready_wait_event, + (atomic_read(&qmi_cfg->fw_ready) && + atomic_read(&qmi_cfg->server_connected)), + msecs_to_jiffies(ATH10K_SNOC_WLAN_FW_READY_TIMEOUT)); + if (ret) { + queue_work(ar->workqueue, &ar->restart_work); + } else { + ath10k_err(ar, "restart failed, fw_ready timed out\n"); + return NOTIFY_OK; + } break; default: ath10k_dbg(ar, ATH10K_DBG_SNOC, @@ -188,17 +201,18 @@ static int ath10k_snoc_modem_notifier_nb(struct notifier_block *nb, struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, modem_ssr_nb); struct ath10k *ar = ar_snoc->ar; + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; - if (notif->crashed) + if (notif->crashed) { atomic_set(&ar_snoc->fw_crashed, 1); + atomic_set(&qmi_cfg->fw_ready, 0); + } ath10k_dbg(ar, ATH10K_DBG_SNOC, "Modem went down %d\n", atomic_read(&ar_snoc->fw_crashed)); - if (notif->crashed) - queue_work(ar->workqueue, &ar->restart_work); return NOTIFY_OK; } @@ -255,6 +269,7 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type, { int ret = 0; int i = 0; + unsigned long irq_flags; struct ath10k *ar = (struct ath10k *)data; struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; @@ -267,7 +282,7 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type, return -EINVAL; } - spin_lock_bh(&qmi_cfg->event_lock); + spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags); for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++) { if (atomic_read(&qmi_cfg->qmi_ev_list[i].event_handled)) { @@ -288,7 +303,7 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type, if (i >= ATH10K_SNOC_DRIVER_EVENT_MAX) i = ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE; - spin_unlock_bh(&qmi_cfg->event_lock); + spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags); queue_work(qmi_cfg->event_wq, &qmi_cfg->event_work); @@ -304,16 +319,16 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type, ath10k_dbg(ar, ATH10K_DBG_SNOC, "Completed event: %s(%d)\n", ath10k_snoc_driver_event_to_str(type), type); - spin_lock_bh(&qmi_cfg->event_lock); + spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags); if (ret == -ERESTARTSYS && qmi_cfg->qmi_ev_list[i].ret == ATH10K_SNOC_EVENT_PENDING) { qmi_cfg->qmi_ev_list[i].sync = false; atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1); - spin_unlock_bh(&qmi_cfg->event_lock); + spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags); ret = -EINTR; goto out; } - spin_unlock_bh(&qmi_cfg->event_lock); + spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags); out: return ret; @@ -714,22 +729,23 @@ static int ath10k_snoc_driver_event_fw_ready_ind(struct ath10k *ar) static void ath10k_snoc_driver_event_work(struct work_struct *work) { - struct ath10k_snoc_qmi_driver_event *event; int ret; + unsigned long irq_flags; + struct ath10k_snoc_qmi_driver_event *event; struct ath10k_snoc_qmi_config *qmi_cfg = container_of(work, struct ath10k_snoc_qmi_config, event_work); struct ath10k_snoc *ar_snoc = container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg); struct ath10k *ar = ar_snoc->ar; - spin_lock_bh(&qmi_cfg->event_lock); + spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags); while (!list_empty(&qmi_cfg->event_list)) { event = list_first_entry(&qmi_cfg->event_list, struct ath10k_snoc_qmi_driver_event, list); list_del(&event->list); - spin_unlock_bh(&qmi_cfg->event_lock); + spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags); ath10k_dbg(ar, ATH10K_DBG_SNOC, "Processing event: %s%s(%d)\n", ath10k_snoc_driver_event_to_str(event->type), @@ -756,17 +772,17 @@ static void ath10k_snoc_driver_event_work(struct work_struct *work) "Event Processed: %s%s(%d), ret: %d\n", ath10k_snoc_driver_event_to_str(event->type), event->sync ? "-sync" : "", event->type, ret); - spin_lock_bh(&qmi_cfg->event_lock); + spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags); if (event->sync) { event->ret = ret; complete(&event->complete); continue; } - spin_unlock_bh(&qmi_cfg->event_lock); - spin_lock_bh(&qmi_cfg->event_lock); + spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags); + spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags); } - spin_unlock_bh(&qmi_cfg->event_lock); + spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags); } static int diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 923fe470360c..476521b77008 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -501,9 +501,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, for (i = 0; i < request->n_ssids; i++) { wil_dbg_misc(wil, "SSID[%d]", i); - print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, - request->ssids[i].ssid, - request->ssids[i].ssid_len); + wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1, + request->ssids[i].ssid, + request->ssids[i].ssid_len, true); } if (request->n_ssids) @@ -540,8 +540,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } if (request->ie_len) - print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET, - request->ie, request->ie_len); + wil_hex_dump_misc("Scan IE ", DUMP_PREFIX_OFFSET, 16, 1, + request->ie, request->ie_len, true); else wil_dbg_misc(wil, "Scan has no IE's\n"); @@ -766,6 +766,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, if (rc == 0) { netif_carrier_on(ndev); wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); + wil->bss = bss; /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); @@ -794,6 +795,7 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return 0; } + wil->locally_generated_disc = true; rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, WMI_DISCONNECT_EVENTID, NULL, 0, WIL6210_DISCONNECT_TO_MS); @@ -847,7 +849,8 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, */ wil_dbg_misc(wil, "mgmt_tx\n"); - print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len); + wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, + len, true); cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!cmd) { @@ -1180,18 +1183,18 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len, static void wil_print_bcon_data(struct cfg80211_beacon_data *b) { - print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET, - b->head, b->head_len); - print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET, - b->tail, b->tail_len); - print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET, - b->beacon_ies, b->beacon_ies_len); - print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET, - b->probe_resp, b->probe_resp_len); - print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET, - b->proberesp_ies, b->proberesp_ies_len); - print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET, - b->assocresp_ies, b->assocresp_ies_len); + wil_hex_dump_misc("head ", DUMP_PREFIX_OFFSET, 16, 1, + b->head, b->head_len, true); + wil_hex_dump_misc("tail ", DUMP_PREFIX_OFFSET, 16, 1, + b->tail, b->tail_len, true); + wil_hex_dump_misc("BCON IE ", DUMP_PREFIX_OFFSET, 16, 1, + b->beacon_ies, b->beacon_ies_len, true); + wil_hex_dump_misc("PROBE ", DUMP_PREFIX_OFFSET, 16, 1, + b->probe_resp, b->probe_resp_len, true); + wil_hex_dump_misc("PROBE IE ", DUMP_PREFIX_OFFSET, 16, 1, + b->proberesp_ies, b->proberesp_ies_len, true); + wil_hex_dump_misc("ASSOC IE ", DUMP_PREFIX_OFFSET, 16, 1, + b->assocresp_ies, b->assocresp_ies_len, true); } /* internal functions for device reset and starting AP */ @@ -1387,8 +1390,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, info->dtim_period); wil_dbg_misc(wil, "PBSS %d\n", info->pbss); - print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, - info->ssid, info->ssid_len); + wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1, + info->ssid, info->ssid_len, true); wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 54d978d884ff..f82bb8964868 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -30,8 +30,8 @@ bool debug_fw; /* = false; */ module_param(debug_fw, bool, 0444); MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug"); -static bool oob_mode; -module_param(oob_mode, bool, 0444); +static u8 oob_mode; +module_param(oob_mode, byte, 0444); MODULE_PARM_DESC(oob_mode, " enable out of the box (OOB) mode in FW, for diagnostics and certification"); @@ -276,11 +276,15 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, if (test_bit(wil_status_fwconnected, wil->status)) { clear_bit(wil_status_fwconnected, wil->status); cfg80211_disconnected(ndev, reason_code, - NULL, 0, false, GFP_KERNEL); + NULL, 0, + wil->locally_generated_disc, + GFP_KERNEL); + wil->locally_generated_disc = false; } else if (test_bit(wil_status_fwconnecting, wil->status)) { cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); + wil->bss = NULL; } clear_bit(wil_status_fwconnecting, wil->status); break; @@ -302,10 +306,34 @@ static void wil_disconnect_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, disconnect_worker); + struct net_device *ndev = wil_to_ndev(wil); + int rc; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_disconnect_event evt; + } __packed reply; - mutex_lock(&wil->mutex); - _wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false); - mutex_unlock(&wil->mutex); + if (test_bit(wil_status_fwconnected, wil->status)) + /* connect succeeded after all */ + return; + + if (!test_bit(wil_status_fwconnecting, wil->status)) + /* already disconnected */ + return; + + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), + WIL6210_DISCONNECT_TO_MS); + if (rc) { + wil_err(wil, "disconnect error %d\n", rc); + return; + } + + wil_update_net_queues_bh(wil, NULL, true); + netif_carrier_off(ndev); + cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); + clear_bit(wil_status_fwconnecting, wil->status); } static void wil_connect_timer_fn(ulong x) @@ -614,13 +642,25 @@ static inline void wil_release_cpu(struct wil6210_priv *wil) wil_w(wil, RGF_USER_USER_CPU_0, 1); } -static void wil_set_oob_mode(struct wil6210_priv *wil, bool enable) +static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode) { - wil_info(wil, "enable=%d\n", enable); - if (enable) + wil_info(wil, "oob_mode to %d\n", mode); + switch (mode) { + case 0: + wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE | + BIT_USER_OOB_R2_MODE); + break; + case 1: + wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE); wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE); - else + break; + case 2: wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE); + wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE); + break; + default: + wil_err(wil, "invalid oob_mode: %d\n", mode); + } } static int wil_target_reset(struct wil6210_priv *wil) @@ -1164,6 +1204,7 @@ void wil_halp_vote(struct wil6210_priv *wil) wil->halp.ref_cnt); if (++wil->halp.ref_cnt == 1) { + reinit_completion(&wil->halp.comp); wil6210_set_halp(wil); rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies); if (!rc) { diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 7260bef314a4..2ae4fe85cc8c 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -71,6 +71,11 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + /* if netif up, hardware is alive, shut it down */ if (ndev->flags & IFF_UP) { rc = wil_down(wil); @@ -86,10 +91,14 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle); - if (rc) + if (rc) { wil_enable_irq(wil); + goto out; + } } + set_bit(wil_status_suspended, wil->status); + out: wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); @@ -117,10 +126,13 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) /* if netif up, bring hardware up * During open(), IFF_UP set after actual device method - * invocation. This prevent recursive call to wil_up() + * invocation. This prevent recursive call to wil_up(). + * wil_status_suspended will be cleared in wil_reset */ if (ndev->flags & IFF_UP) rc = wil_up(wil); + else + clear_bit(wil_status_suspended, wil->status); out: wil_dbg_pm(wil, "resume: %s => %d\n", diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 6111ef6408ea..cf9ed143fdf4 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -141,6 +141,7 @@ struct RGF_ICR { #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_6 (0x880018) #define BIT_USER_OOB_MODE BIT(31) + #define BIT_USER_OOB_R2_MODE BIT(30) #define RGF_USER_USAGE_8 (0x880020) #define BIT_USER_PREVENT_DEEP_SLEEP BIT(0) #define BIT_USER_SUPPORT_T_POWER_ON_0 BIT(1) @@ -417,6 +418,7 @@ enum { /* for wil6210_priv.status */ wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ wil_status_resetting, /* reset in progress */ + wil_status_suspended, /* suspend completed, device is suspended */ wil_status_last /* keep last */ }; @@ -620,6 +622,8 @@ struct wil6210_priv { u16 channel; /* relevant in AP mode */ int sinfo_gen; u32 ap_isolate; /* no intra-BSS communication */ + struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */ + int locally_generated_disc; /* relevant in STA mode */ /* interrupt moderation */ u32 tx_max_burst_duration; u32 tx_interframe_timeout; @@ -777,6 +781,12 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) print_hex_dump_debug("DBG[ WMI]" prefix_str,\ prefix_type, rowsize, \ groupsize, buf, len, ascii) + +#define wil_hex_dump_misc(prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) \ + print_hex_dump_debug("DBG[MISC]" prefix_str,\ + prefix_type, rowsize, \ + groupsize, buf, len, ascii) #else /* defined(CONFIG_DYNAMIC_DEBUG) */ static inline void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize, @@ -789,6 +799,12 @@ void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii) { } + +static inline +void wil_hex_dump_misc(const char *prefix_str, int prefix_type, int rowsize, + int groupsize, const void *buf, size_t len, bool ascii) +{ +} #endif /* defined(CONFIG_DYNAMIC_DEBUG) */ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 6a6ba02beba0..01a80a7b981e 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -573,12 +573,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) GFP_KERNEL); goto out; } else { - cfg80211_connect_result(ndev, evt->bssid, - assoc_req_ie, assoc_req_ielen, - assoc_resp_ie, assoc_resp_ielen, - WLAN_STATUS_SUCCESS, - GFP_KERNEL); + struct wiphy *wiphy = wil_to_wiphy(wil); + + cfg80211_ref_bss(wiphy, wil->bss); + cfg80211_connect_bss(ndev, evt->bssid, wil->bss, + assoc_req_ie, assoc_req_ielen, + assoc_resp_ie, assoc_resp_ielen, + WLAN_STATUS_SUCCESS, GFP_KERNEL, + NL80211_TIMEOUT_UNSPECIFIED); } + wil->bss = NULL; } else if ((wdev->iftype == NL80211_IFTYPE_AP) || (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { if (rc) { @@ -1524,6 +1528,7 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason); + wil->locally_generated_disc = true; if (del_sta) { ether_addr_copy(del_sta_cmd.dst_mac, mac); rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd, diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 72695d3b9224..9dc678ce4a48 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -481,6 +481,11 @@ enum msm_pcie_link_status { MSM_PCIE_LINK_DISABLED }; +enum msm_pcie_boot_option { + MSM_PCIE_NO_PROBE_ENUMERATION = BIT(0), + MSM_PCIE_NO_WAKE_ENUMERATION = BIT(1) +}; + /* gpio info structure */ struct msm_pcie_gpio_info_t { char *name; @@ -629,7 +634,7 @@ struct msm_pcie_dev_t { uint32_t perst_delay_us_max; uint32_t tlp_rd_size; bool linkdown_panic; - bool ep_wakeirq; + uint32_t boot_option; uint32_t rc_idx; uint32_t phy_ver; @@ -1947,8 +1952,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->aer_enable ? "" : "not"); PCIE_DBG_FS(dev, "ext_ref_clk is %d\n", dev->ext_ref_clk); - PCIE_DBG_FS(dev, "ep_wakeirq is %d\n", - dev->ep_wakeirq); + PCIE_DBG_FS(dev, "boot_option is 0x%x\n", + dev->boot_option); PCIE_DBG_FS(dev, "phy_ver is %d\n", dev->phy_ver); PCIE_DBG_FS(dev, "drv_ready is %d\n", @@ -2563,7 +2568,7 @@ static struct dentry *dfile_linkdown_panic; static struct dentry *dfile_wr_offset; static struct dentry *dfile_wr_mask; static struct dentry *dfile_wr_value; -static struct dentry *dfile_ep_wakeirq; +static struct dentry *dfile_boot_option; static struct dentry *dfile_aer_enable; static struct dentry *dfile_corr_counter_limit; @@ -2832,13 +2837,13 @@ const struct file_operations msm_pcie_wr_value_ops = { .write = msm_pcie_set_wr_value, }; -static ssize_t msm_pcie_set_ep_wakeirq(struct file *file, +static ssize_t msm_pcie_set_boot_option(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long ret; char str[MAX_MSG_LEN]; - u32 new_ep_wakeirq = 0; + u32 new_boot_option = 0; int i; memset(str, 0, sizeof(str)); @@ -2847,33 +2852,33 @@ static ssize_t msm_pcie_set_ep_wakeirq(struct file *file, return -EFAULT; for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) - new_ep_wakeirq = (new_ep_wakeirq * 10) + (str[i] - '0'); + new_boot_option = (new_boot_option * 10) + (str[i] - '0'); - if (new_ep_wakeirq <= 1) { + if (new_boot_option <= 1) { for (i = 0; i < MAX_RC_NUM; i++) { if (!rc_sel) { - msm_pcie_dev[0].ep_wakeirq = new_ep_wakeirq; + msm_pcie_dev[0].boot_option = new_boot_option; PCIE_DBG_FS(&msm_pcie_dev[0], - "PCIe: RC0: ep_wakeirq is now %d\n", - msm_pcie_dev[0].ep_wakeirq); + "PCIe: RC0: boot_option is now 0x%x\n", + msm_pcie_dev[0].boot_option); break; } else if (rc_sel & (1 << i)) { - msm_pcie_dev[i].ep_wakeirq = new_ep_wakeirq; + msm_pcie_dev[i].boot_option = new_boot_option; PCIE_DBG_FS(&msm_pcie_dev[i], - "PCIe: RC%d: ep_wakeirq is now %d\n", - i, msm_pcie_dev[i].ep_wakeirq); + "PCIe: RC%d: boot_option is now 0x%x\n", + i, msm_pcie_dev[i].boot_option); } } } else { - pr_err("PCIe: Invalid input for ep_wakeirq: %d. Please enter 0 or 1.\n", - new_ep_wakeirq); + pr_err("PCIe: Invalid input for boot_option: 0x%x.\n", + new_boot_option); } return count; } -const struct file_operations msm_pcie_ep_wakeirq_ops = { - .write = msm_pcie_set_ep_wakeirq, +const struct file_operations msm_pcie_boot_option_ops = { + .write = msm_pcie_set_boot_option, }; static ssize_t msm_pcie_set_aer_enable(struct file *file, @@ -3026,12 +3031,12 @@ static void msm_pcie_debugfs_init(void) goto wr_value_error; } - dfile_ep_wakeirq = debugfs_create_file("ep_wakeirq", 0664, + dfile_boot_option = debugfs_create_file("boot_option", 0664, dent_msm_pcie, 0, - &msm_pcie_ep_wakeirq_ops); - if (!dfile_ep_wakeirq || IS_ERR(dfile_ep_wakeirq)) { - pr_err("PCIe: fail to create the file for debug_fs ep_wakeirq.\n"); - goto ep_wakeirq_error; + &msm_pcie_boot_option_ops); + if (!dfile_boot_option || IS_ERR(dfile_boot_option)) { + pr_err("PCIe: fail to create the file for debug_fs boot_option.\n"); + goto boot_option_error; } dfile_aer_enable = debugfs_create_file("aer_enable", 0664, @@ -3054,8 +3059,8 @@ static void msm_pcie_debugfs_init(void) corr_counter_limit_error: debugfs_remove(dfile_aer_enable); aer_enable_error: - debugfs_remove(dfile_ep_wakeirq); -ep_wakeirq_error: + debugfs_remove(dfile_boot_option); +boot_option_error: debugfs_remove(dfile_wr_value); wr_value_error: debugfs_remove(dfile_wr_mask); @@ -3082,7 +3087,7 @@ static void msm_pcie_debugfs_exit(void) debugfs_remove(dfile_wr_offset); debugfs_remove(dfile_wr_mask); debugfs_remove(dfile_wr_value); - debugfs_remove(dfile_ep_wakeirq); + debugfs_remove(dfile_boot_option); debugfs_remove(dfile_aer_enable); debugfs_remove(dfile_corr_counter_limit); } @@ -3313,7 +3318,7 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, word_offset = where & ~0x3; byte_offset = where & 0x3; - mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset); + mask = ((u32)~0 >> (8 * (4 - size))) << (8 * byte_offset); if (rc || !dev->enumerated) { config_base = rc ? dev->dm_core : dev->conf; @@ -3348,12 +3353,17 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, writel_relaxed(wr_val, config_base + word_offset); wmb(); /* ensure config data is written to hardware register */ - if (rd_val == PCIE_LINK_DOWN) - PCIE_ERR(dev, - "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", - rc_idx, bus->number, devfn, where, size); - else if (dev->shadow_en) - msm_pcie_save_shadow(dev, word_offset, wr_val, bdf, rc); + if (dev->shadow_en) { + if (rd_val == PCIE_LINK_DOWN && + (readl_relaxed(config_base) == PCIE_LINK_DOWN)) + PCIE_ERR(dev, + "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", + rc_idx, bus->number, devfn, + where, size); + else + msm_pcie_save_shadow(dev, word_offset, wr_val, + bdf, rc); + } PCIE_DBG3(dev, "RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n", @@ -5411,14 +5421,10 @@ static irqreturn_t handle_wake_irq(int irq, void *data) PCIE_DBG2(dev, "PCIe WAKE is asserted by Endpoint of RC%d\n", dev->rc_idx); - if (!dev->enumerated) { - PCIE_DBG(dev, "Start enumeating RC%d\n", dev->rc_idx); - if (dev->ep_wakeirq) - schedule_work(&dev->handle_wake_work); - else - PCIE_DBG(dev, - "wake irq is received but ep_wakeirq is not supported for RC%d.\n", - dev->rc_idx); + if (!dev->enumerated && !(dev->boot_option & + MSM_PCIE_NO_WAKE_ENUMERATION)) { + PCIE_DBG(dev, "Start enumerating RC%d\n", dev->rc_idx); + schedule_work(&dev->handle_wake_work); } else { PCIE_DBG2(dev, "Wake up RC%d\n", dev->rc_idx); __pm_stay_awake(&dev->ws); @@ -5562,7 +5568,7 @@ static irqreturn_t handle_global_irq(int irq, void *data) handle_aer_irq(irq, data); break; default: - PCIE_ERR(dev, + PCIE_DUMP(dev, "PCIe: RC%d: Unexpected event %d is caught!\n", dev->rc_idx, i); } @@ -6200,12 +6206,12 @@ static int msm_pcie_probe(struct platform_device *pdev) msm_pcie_dev[rc_idx].rc_idx, msm_pcie_dev[rc_idx].smmu_sid_base); - msm_pcie_dev[rc_idx].ep_wakeirq = - of_property_read_bool((&pdev->dev)->of_node, - "qcom,ep-wakeirq"); + msm_pcie_dev[rc_idx].boot_option = 0; + ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,boot-option", + &msm_pcie_dev[rc_idx].boot_option); PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: EP of RC%d does %s assert wake when it is up.\n", - rc_idx, msm_pcie_dev[rc_idx].ep_wakeirq ? "" : "not"); + "PCIe: RC%d boot option is 0x%x.\n", + rc_idx, msm_pcie_dev[rc_idx].boot_option); msm_pcie_dev[rc_idx].phy_ver = 1; ret = of_property_read_u32((&pdev->dev)->of_node, @@ -6484,9 +6490,10 @@ static int msm_pcie_probe(struct platform_device *pdev) msm_pcie_dev[rc_idx].drv_ready = true; - if (msm_pcie_dev[rc_idx].ep_wakeirq) { + if (msm_pcie_dev[rc_idx].boot_option & + MSM_PCIE_NO_PROBE_ENUMERATION) { PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: RC%d will be enumerated upon WAKE signal from Endpoint.\n", + "PCIe: RC%d will be enumerated by client or endpoint.\n", rc_idx); mutex_unlock(&pcie_drv.drv_lock); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 553480660722..100bbd582a5e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3848,11 +3848,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, } ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); - if (ipa_ctx->logbuf == NULL) { - IPAERR("failed to get logbuf\n"); - result = -ENOMEM; - goto fail_logbuf; - } + if (ipa_ctx->logbuf == NULL) + IPAERR("failed to create IPC log, continue...\n"); ipa_ctx->pdev = ipa_dev; ipa_ctx->uc_pdev = ipa_dev; @@ -4390,8 +4387,8 @@ fail_bus_reg: fail_bind: kfree(ipa_ctx->ctrl); fail_mem_ctrl: - ipc_log_context_destroy(ipa_ctx->logbuf); -fail_logbuf: + if (ipa_ctx->logbuf) + ipc_log_context_destroy(ipa_ctx->logbuf); kfree(ipa_ctx); ipa_ctx = NULL; fail_mem_ctx: diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index f8f8fd12161a..5c07bc7d43b5 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -562,6 +562,8 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, mutex_unlock(&ipa_ctx->msg_lock); if (copy_to_user(buf, &msg->meta, sizeof(struct ipa_msg_meta))) { + kfree(msg); + msg = NULL; ret = -EFAULT; break; } @@ -570,6 +572,8 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, if (msg->buff) { if (copy_to_user(buf, msg->buff, msg->meta.msg_len)) { + kfree(msg); + msg = NULL; ret = -EFAULT; break; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 5b706b6f493b..ddff50834f03 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4264,11 +4264,8 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, } ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); - if (ipa3_ctx->logbuf == NULL) { - IPAERR("failed to get logbuf\n"); - result = -ENOMEM; - goto fail_logbuf; - } + if (ipa3_ctx->logbuf == NULL) + IPAERR("failed to create IPC log, continue...\n"); ipa3_ctx->pdev = ipa_dev; ipa3_ctx->uc_pdev = ipa_dev; @@ -4769,8 +4766,8 @@ fail_bind: fail_mem_ctrl: kfree(ipa3_ctx->ipa_tz_unlock_reg); fail_tz_unlock_reg: - ipc_log_context_destroy(ipa3_ctx->logbuf); -fail_logbuf: + if (ipa3_ctx->logbuf) + ipc_log_context_destroy(ipa3_ctx->logbuf); kfree(ipa3_ctx); ipa3_ctx = NULL; fail_mem_ctx: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index b687b711dc20..16a567644f79 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -572,6 +572,8 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, if (copy_to_user(buf, &msg->meta, sizeof(struct ipa_msg_meta))) { ret = -EFAULT; + kfree(msg); + msg = NULL; break; } buf += sizeof(struct ipa_msg_meta); @@ -580,6 +582,8 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, if (copy_to_user(buf, msg->buff, msg->meta.msg_len)) { ret = -EFAULT; + kfree(msg); + msg = NULL; break; } buf += msg->meta.msg_len; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 6731150ce4e7..e3f8f4c0be46 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2365,32 +2365,41 @@ static int rmnet_ipa_ap_suspend(struct device *dev) { struct net_device *netdev = IPA_NETDEV(); struct ipa3_wwan_private *wwan_ptr; + int ret; + + IPAWANDBG("Enter...\n"); - IPAWANDBG_LOW("Enter...\n"); if (netdev == NULL) { IPAWANERR("netdev is NULL.\n"); - return 0; + ret = 0; + goto bail; } + netif_tx_lock_bh(netdev); wwan_ptr = netdev_priv(netdev); if (wwan_ptr == NULL) { IPAWANERR("wwan_ptr is NULL.\n"); - return 0; + ret = 0; + goto unlock_and_bail; } /* Do not allow A7 to suspend in case there are oustanding packets */ if (atomic_read(&wwan_ptr->outstanding_pkts) != 0) { IPAWANDBG("Outstanding packets, postponing AP suspend.\n"); - return -EAGAIN; + ret = -EAGAIN; + goto unlock_and_bail; } /* Make sure that there is no Tx operation ongoing */ - netif_tx_lock_bh(netdev); + netif_stop_queue(netdev); ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD); - netif_tx_unlock_bh(netdev); - IPAWANDBG_LOW("Exit\n"); + ret = 0; - return 0; +unlock_and_bail: + netif_tx_unlock_bh(netdev); +bail: + IPAWANDBG("Exit with %d\n", ret); + return ret; } /** @@ -2407,10 +2416,10 @@ static int rmnet_ipa_ap_resume(struct device *dev) { struct net_device *netdev = IPA_NETDEV(); - IPAWANDBG_LOW("Enter...\n"); + IPAWANDBG("Enter...\n"); if (netdev) netif_wake_queue(netdev); - IPAWANDBG_LOW("Exit\n"); + IPAWANDBG("Exit\n"); return 0; } diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index ab3c3503c2fc..3191ec065a95 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -1185,9 +1185,43 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info) mutex_unlock(&chan_attr->chan_lock); wake_up(&chan_attr->wq); break; + case MHI_CB_SYS_ERROR: + case MHI_CB_MHI_SHUTDOWN: case MHI_CB_MHI_DISABLED: uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, - "MHI disabled CB received\n"); + "MHI disabled CB received 0x%x for chan:%d\n", + cb_info->cb_reason, cb_info->chan); + + chan_attr = (cb_info->chan % 2) ? &uci_handle->in_attr : + &uci_handle->out_attr; + mutex_lock(&chan_attr->chan_lock); + chan_attr->enabled = false; + /* we disable entire handler by grabbing only one lock */ + uci_handle->enabled = false; + mutex_unlock(&chan_attr->chan_lock); + wake_up(&chan_attr->wq); + + /* + * if it's ctrl channel clear the resource now + * otherwise during file close we will release the + * resources + */ + if (uci_handle == uci_handle->uci_ctxt->ctrl_client && + chan_attr == &uci_handle->out_attr) { + struct uci_buf *itr, *tmp; + + mutex_lock(&chan_attr->chan_lock); + atomic_set(&uci_handle->out_attr.avail_pkts, 0); + atomic_set(&uci_handle->out_pkt_pend_ack, 0); + list_for_each_entry_safe(itr, tmp, &chan_attr->buf_head, + node) { + list_del(&itr->node); + kfree(itr->data); + } + atomic_set(&uci_handle->completion_ack, 0); + INIT_LIST_HEAD(&uci_handle->out_attr.buf_head); + mutex_unlock(&chan_attr->chan_lock); + } break; case MHI_CB_XFER: if (!cb_info->result) { diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c index 9b6096485c39..d0f21943cb0f 100644 --- a/drivers/platform/msm/seemp_core/seemp_logk.c +++ b/drivers/platform/msm/seemp_core/seemp_logk.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -184,6 +184,8 @@ static int seemp_logk_usr_record(const char __user *buf, size_t count) if (copy_from_user(&usr_blk.payload, &local_blk->payload, sizeof(struct blk_payload)) != 0) return -EFAULT; + } else { + return -EFAULT; } idx = ret = 0; now = current_kernel_time(); @@ -283,7 +285,12 @@ static bool seemp_logk_get_bit_from_vector(__u8 *pVec, __u32 index) { unsigned int byte_num = index/8; unsigned int bit_num = index%8; - unsigned char byte = pVec[byte_num]; + unsigned char byte; + + if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE) + return false; + + byte = pVec[byte_num]; return !(byte & (1 << bit_num)); } diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 3ac4611da9bd..43ad33ea234b 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1069,6 +1069,7 @@ static int msm_core_dev_probe(struct platform_device *pdev) if (ret) goto failed; + INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle); ret = msm_core_task_init(&pdev->dev); if (ret) goto failed; @@ -1076,7 +1077,6 @@ static int msm_core_dev_probe(struct platform_device *pdev) for_each_possible_cpu(cpu) set_threshold(&activity[cpu]); - INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle); schedule_delayed_work(&sampling_work, msecs_to_jiffies(0)); cpufreq_register_notifier(&cpu_policy, CPUFREQ_POLICY_NOTIFIER); pm_notifier(system_suspend_handler, 0); diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 914a6e4eae64..67f9d4fafeb8 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -511,13 +511,14 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, return 0; } -#define ICL_STEP_UV 25000 +#define ICL_STEP_UA 25000 static int usb_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { int rc; struct pl_data *chip = data; union power_supply_propval pval = {0, }; + bool rerun_aicl = false; if (!chip->main_psy) return 0; @@ -543,22 +544,28 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, } /* rerun AICL if new ICL is above settled ICL */ - if (icl_ua > pval.intval) { + if (icl_ua > pval.intval) + rerun_aicl = true; + + if (rerun_aicl) { /* set a lower ICL */ - pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV); + pval.intval = max(pval.intval - ICL_STEP_UA, ICL_STEP_UA); power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); /* wait for ICL change */ msleep(100); + } - pval.intval = icl_ua; - power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, - &pval); + /* set the effective ICL */ + pval.intval = icl_ua; + power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, + &pval); + if (rerun_aicl) /* wait for ICL change */ msleep(100); - } + vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); return 0; diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index f2047592a94b..316313ff6408 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -162,6 +162,7 @@ enum fg_sram_param_id { FG_SRAM_ESR_TIMER_DISCHG_INIT, FG_SRAM_ESR_TIMER_CHG_MAX, FG_SRAM_ESR_TIMER_CHG_INIT, + FG_SRAM_ESR_PULSE_THRESH, FG_SRAM_SYS_TERM_CURR, FG_SRAM_CHG_TERM_CURR, FG_SRAM_DELTA_MSOC_THR, @@ -253,6 +254,8 @@ struct fg_dt_props { int esr_tight_lt_flt_upct; int esr_broad_lt_flt_upct; int slope_limit_temp; + int esr_pulse_thresh_ma; + int esr_meas_curr_ma; int jeita_thresholds[NUM_JEITA_LEVELS]; int ki_coeff_soc[KI_COEFF_SOC_LEVELS]; int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS]; diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h index bf2827fb550d..cd0b2fb4391f 100644 --- a/drivers/power/supply/qcom/fg-reg.h +++ b/drivers/power/supply/qcom/fg-reg.h @@ -167,6 +167,7 @@ /* BATT_INFO_ESR_PULL_DN_CFG */ #define ESR_PULL_DOWN_IVAL_MASK GENMASK(3, 2) +#define ESR_PULL_DOWN_IVAL_SHIFT 2 #define ESR_MEAS_CUR_60MA 0x0 #define ESR_MEAS_CUR_120MA 0x1 #define ESR_MEAS_CUR_180MA 0x2 diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 59216a567662..2e9425040f72 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -31,6 +31,8 @@ #define FG_MEM_INFO_PMI8998 0x0D /* SRAM address and offset in ascending order */ +#define ESR_PULSE_THRESH_WORD 2 +#define ESR_PULSE_THRESH_OFFSET 3 #define SLOPE_LIMIT_WORD 3 #define SLOPE_LIMIT_OFFSET 0 #define CUTOFF_VOLT_WORD 5 @@ -216,6 +218,8 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = { ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD, ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), + PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET, + 1, 100000, 390625, 0, fg_encode_default, NULL), PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_WORD, KI_COEFF_MED_DISCHG_OFFSET, 1, 1000, 244141, 0, fg_encode_default, NULL), @@ -286,6 +290,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD, ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL), + PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET, + 1, 100000, 390625, 0, fg_encode_default, NULL), PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_v2_WORD, KI_COEFF_MED_DISCHG_v2_OFFSET, 1, 1000, 244141, 0, fg_encode_default, NULL), @@ -981,6 +987,29 @@ static inline void get_batt_temp_delta(int delta, u8 *val) }; } +static inline void get_esr_meas_current(int curr_ma, u8 *val) +{ + switch (curr_ma) { + case 60: + *val = ESR_MEAS_CUR_60MA; + break; + case 120: + *val = ESR_MEAS_CUR_120MA; + break; + case 180: + *val = ESR_MEAS_CUR_180MA; + break; + case 240: + *val = ESR_MEAS_CUR_240MA; + break; + default: + *val = ESR_MEAS_CUR_120MA; + break; + }; + + *val <<= ESR_PULL_DOWN_IVAL_SHIFT; +} + static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging, int flags) { @@ -2189,6 +2218,35 @@ static int fg_get_cycle_count(struct fg_chip *chip) return count; } +static int fg_bp_params_config(struct fg_chip *chip) +{ + int rc = 0; + u8 buf; + + /* This SRAM register is only present in v2.0 and above */ + if (!(chip->wa_flags & PMI8998_V1_REV_WA) && + chip->bp.float_volt_uv > 0) { + fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT, + chip->bp.float_volt_uv / 1000, &buf); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word, + chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf, + chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing float_volt, rc=%d\n", rc); + return rc; + } + } + + if (chip->bp.vbatt_full_mv > 0) { + rc = fg_set_constant_chg_voltage(chip, + chip->bp.vbatt_full_mv * 1000); + if (rc < 0) + return rc; + } + + return rc; +} + #define PROFILE_LOAD_BIT BIT(0) #define BOOTLOADER_LOAD_BIT BIT(1) #define BOOTLOADER_RESTART_BIT BIT(2) @@ -2367,6 +2425,11 @@ static void profile_load_work(struct work_struct *work) } done: + rc = fg_bp_params_config(chip); + if (rc < 0) + pr_err("Error in configuring battery profile params, rc:%d\n", + rc); + rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2, FG_IMA_DEFAULT); if (rc < 0) { @@ -3018,27 +3081,6 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - /* This SRAM register is only present in v2.0 and above */ - if (!(chip->wa_flags & PMI8998_V1_REV_WA) && - chip->bp.float_volt_uv > 0) { - fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT, - chip->bp.float_volt_uv / 1000, buf); - rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word, - chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, buf, - chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in writing float_volt, rc=%d\n", rc); - return rc; - } - } - - if (chip->bp.vbatt_full_mv > 0) { - rc = fg_set_constant_chg_voltage(chip, - chip->bp.vbatt_full_mv * 1000); - if (rc < 0) - return rc; - } - fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word, @@ -3234,6 +3276,24 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } + fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH, + chip->dt.esr_pulse_thresh_ma, buf); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word, + chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf, + chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc); + return rc; + } + + get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val); + rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip), + ESR_PULL_DOWN_IVAL_MASK, val); + if (rc < 0) { + pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc); + return rc; + } + return 0; } @@ -3717,6 +3777,8 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip) #define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829 #define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438 #define DEFAULT_ESR_CLAMP_MOHMS 20 +#define DEFAULT_ESR_PULSE_THRESH_MA 110 +#define DEFAULT_ESR_MEAS_CURR_MA 120 static int fg_parse_dt(struct fg_chip *chip) { struct device_node *child, *revid_node, *node = chip->dev->of_node; @@ -4035,6 +4097,22 @@ static int fg_parse_dt(struct fg_chip *chip) else chip->dt.esr_clamp_mohms = temp; + chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA; + rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp); + if (!rc) { + /* ESR pulse qualification threshold range is 1-997 mA */ + if (temp > 0 && temp < 997) + chip->dt.esr_pulse_thresh_ma = temp; + } + + chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA; + rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp); + if (!rc) { + /* ESR measurement current range is 60-240 mA */ + if (temp >= 60 || temp <= 240) + chip->dt.esr_meas_curr_ma = temp; + } + return 0; } diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 4dfa43012b54..81e656c06da0 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -2233,7 +2233,7 @@ static int smb2_probe(struct platform_device *pdev) rc = smblib_get_prop_batt_health(chg, &val); if (rc < 0) { pr_err("Couldn't get batt health rc=%d\n", rc); - goto cleanup; + val.intval = POWER_SUPPLY_HEALTH_UNKNOWN; } batt_health = val.intval; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index bd96703579f6..14e9c3a2254d 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1532,6 +1532,19 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, break; } + if (val->intval != POWER_SUPPLY_STATUS_CHARGING) + return 0; + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", + rc); + return rc; + } + + if (stat & (BAT_TEMP_STATUS_TOO_HOT_BIT | BAT_TEMP_STATUS_TOO_COLD_BIT)) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + return 0; } diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index 167666a8c548..3f260a407721 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -1025,4 +1025,14 @@ enum { /* CHGR FREQ Peripheral registers */ #define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50) +/* SMB1355 specific registers */ +#define SMB1355_TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) +#define SKIN_TEMP_RST_HOT_BIT BIT(6) +#define SKIN_TEMP_UB_HOT_BIT BIT(5) +#define SKIN_TEMP_LB_HOT_BIT BIT(4) +#define DIE_TEMP_TSD_HOT_BIT BIT(3) +#define DIE_TEMP_RST_HOT_BIT BIT(2) +#define DIE_TEMP_UB_HOT_BIT BIT(1) +#define DIE_TEMP_LB_HOT_BIT BIT(0) + #endif /* __SMB2_CHARGER_REG_H */ diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 4916c87aced8..4e710cae6b78 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -104,6 +104,8 @@ struct smb138x { struct smb_dt_props dt; struct power_supply *parallel_psy; u32 wa_flags; + struct pmic_revid_data *pmic_rev_id; + char *name; }; static int __debug_mask; @@ -167,6 +169,14 @@ static int smb138x_parse_dt(struct smb138x *chip) if (rc < 0) chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID; + /* check that smb1355 is configured to run in mid-mid mode */ + if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE + && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) { + pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n", + chip->dt.pl_mode); + return -EINVAL; + } + chip->dt.suspend_input = of_property_read_bool(node, "qcom,suspend-input"); @@ -479,6 +489,30 @@ static int smb138x_init_batt_psy(struct smb138x *chip) * PARALLEL PSY REGISTRATION * *****************************/ +static int smb1355_get_prop_connector_health(struct smb138x *chip) +{ + struct smb_charger *chg = &chip->chg; + u8 temp; + int rc; + + rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp); + if (rc < 0) { + pr_err("Couldn't read comp stat reg rc = %d\n", rc); + return POWER_SUPPLY_HEALTH_UNKNOWN; + } + + if (temp & SKIN_TEMP_RST_HOT_BIT) + return POWER_SUPPLY_HEALTH_OVERHEAT; + + if (temp & SKIN_TEMP_UB_HOT_BIT) + return POWER_SUPPLY_HEALTH_HOT; + + if (temp & SKIN_TEMP_LB_HOT_BIT) + return POWER_SUPPLY_HEALTH_WARM; + + return POWER_SUPPLY_HEALTH_COOL; +} + static int smb138x_get_prop_connector_health(struct smb138x *chip) { struct smb_charger *chg = &chip->chg; @@ -536,16 +570,32 @@ static enum power_supply_property smb138x_parallel_props[] = { POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, - POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, - POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_PARALLEL_MODE, + POWER_SUPPLY_PROP_CONNECTOR_HEALTH, + POWER_SUPPLY_PROP_SET_SHIP_MODE, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, +}; + +static enum power_supply_property smb1355_parallel_props[] = { + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_PIN_ENABLED, + POWER_SUPPLY_PROP_INPUT_SUSPEND, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, POWER_SUPPLY_PROP_SET_SHIP_MODE, + POWER_SUPPLY_PROP_CHARGER_TEMP, + POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, }; static int smb138x_parallel_get_prop(struct power_supply *psy, @@ -577,18 +627,12 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, rc = smblib_get_usb_suspend(chg, &val->intval); break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) rc = smblib_get_prop_input_current_limited(chg, val); else val->intval = 0; break; - case POWER_SUPPLY_PROP_CURRENT_MAX: - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - rc = smblib_get_charge_param(chg, &chg->param.usb_icl, - &val->intval); - else - val->intval = 0; - break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval); break; @@ -596,28 +640,46 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, rc = smblib_get_charge_param(chg, &chg->param.fcc, &val->intval); break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = smblib_get_prop_slave_current_now(chg, val); - break; - case POWER_SUPPLY_PROP_CHARGER_TEMP: - rc = smb138x_get_prop_charger_temp(chip, val); - break; - case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: - rc = smblib_get_prop_charger_temp_max(chg, val); - break; case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = "smb138x"; + val->strval = chip->name; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: val->intval = chip->dt.pl_mode; break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: - val->intval = smb138x_get_prop_connector_health(chip); + if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) + val->intval = smb138x_get_prop_connector_health(chip); + else + val->intval = smb1355_get_prop_connector_health(chip); break; case POWER_SUPPLY_PROP_SET_SHIP_MODE: /* Not in ship mode as long as device is active */ val->intval = 0; break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) + rc = smb138x_get_prop_charger_temp(chip, val); + else + rc = smblib_get_prop_charger_temp(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: + rc = smblib_get_prop_charger_temp_max(chg, val); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) + rc = smblib_get_prop_slave_current_now(chg, val); + else + rc = -ENODATA; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) + && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))) + rc = smblib_get_charge_param(chg, &chg->param.usb_icl, + &val->intval); + else + rc = -ENODATA; + break; default: pr_err("parallel power supply get prop %d not supported\n", prop); @@ -669,7 +731,8 @@ static int smb138x_parallel_set_prop(struct power_supply *psy, rc = smb138x_set_parallel_suspend(chip, (bool)val->intval); break; case POWER_SUPPLY_PROP_CURRENT_MAX: - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) rc = smblib_set_charge_param(chg, &chg->param.usb_icl, val->intval); break; @@ -700,7 +763,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy, return 0; } -static const struct power_supply_desc parallel_psy_desc = { +static struct power_supply_desc parallel_psy_desc = { .name = "parallel", .type = POWER_SUPPLY_TYPE_PARALLEL, .properties = smb138x_parallel_props, @@ -728,6 +791,28 @@ static int smb138x_init_parallel_psy(struct smb138x *chip) return 0; } +static int smb1355_init_parallel_psy(struct smb138x *chip) +{ + struct power_supply_config parallel_cfg = {}; + struct smb_charger *chg = &chip->chg; + + parallel_cfg.drv_data = chip; + parallel_cfg.of_node = chg->dev->of_node; + + /* change to smb1355's property list */ + parallel_psy_desc.properties = smb1355_parallel_props; + parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props); + chip->parallel_psy = devm_power_supply_register(chg->dev, + ¶llel_psy_desc, + ¶llel_cfg); + if (IS_ERR(chip->parallel_psy)) { + pr_err("Couldn't register parallel power supply\n"); + return PTR_ERR(chip->parallel_psy); + } + + return 0; +} + /****************************** * VBUS REGULATOR REGISTRATION * ******************************/ @@ -1047,7 +1132,6 @@ static int smb138x_init_hw(struct smb138x *chip) static int smb138x_setup_wa_flags(struct smb138x *chip) { - struct pmic_revid_data *pmic_rev_id; struct device_node *revid_dev_node; revid_dev_node = of_parse_phandle(chip->chg.dev->of_node, @@ -1057,8 +1141,8 @@ static int smb138x_setup_wa_flags(struct smb138x *chip) return -EINVAL; } - pmic_rev_id = get_revid_data(revid_dev_node); - if (IS_ERR_OR_NULL(pmic_rev_id)) { + chip->pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR_OR_NULL(chip->pmic_rev_id)) { /* * the revid peripheral must be registered, any failure * here only indicates that the rev-id module has not @@ -1067,14 +1151,14 @@ static int smb138x_setup_wa_flags(struct smb138x *chip) return -EPROBE_DEFER; } - switch (pmic_rev_id->pmic_subtype) { + switch (chip->pmic_rev_id->pmic_subtype) { case SMB1381_SUBTYPE: - if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */ + if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */ chip->wa_flags |= OOB_COMP_WA_BIT; break; default: pr_err("PMIC subtype %d not supported\n", - pmic_rev_id->pmic_subtype); + chip->pmic_rev_id->pmic_subtype); return -EINVAL; } @@ -1372,6 +1456,7 @@ static int smb138x_master_probe(struct smb138x *chip) chg->param = v1_params; + chip->name = "smb1381"; rc = smblib_init(chg); if (rc < 0) { pr_err("Couldn't initialize smblib rc=%d\n", rc); @@ -1432,7 +1517,7 @@ static int smb138x_master_probe(struct smb138x *chip) return rc; } -static int smb138x_slave_probe(struct smb138x *chip) +static int smb1355_slave_probe(struct smb138x *chip) { struct smb_charger *chg = &chip->chg; int rc = 0; @@ -1445,6 +1530,55 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } + rc = smb138x_parse_dt(chip); + if (rc < 0) { + pr_err("Couldn't parse device tree rc=%d\n", rc); + goto cleanup; + } + + rc = smb138x_init_slave_hw(chip); + if (rc < 0) { + pr_err("Couldn't initialize hardware rc=%d\n", rc); + goto cleanup; + } + + rc = smb1355_init_parallel_psy(chip); + if (rc < 0) { + pr_err("Couldn't initialize parallel psy rc=%d\n", rc); + goto cleanup; + } + + rc = smb138x_determine_initial_slave_status(chip); + if (rc < 0) { + pr_err("Couldn't determine initial status rc=%d\n", rc); + goto cleanup; + } + + rc = smb138x_request_interrupts(chip); + if (rc < 0) { + pr_err("Couldn't request interrupts rc=%d\n", rc); + goto cleanup; + } + + return 0; + +cleanup: + smblib_deinit(chg); + return rc; +} + +static int smb1381_slave_probe(struct smb138x *chip) +{ + struct smb_charger *chg = &chip->chg; + int rc = 0; + + chg->param = v1_params; + + rc = smblib_init(chg); + if (rc < 0) { + pr_err("Couldn't initialize smblib rc=%d\n", rc); + goto cleanup; + } chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max"); if (IS_ERR(chg->iio.temp_max_chan)) { rc = PTR_ERR(chg->iio.temp_max_chan); @@ -1484,7 +1618,8 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) { + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { rc = smb138x_init_vbus_regulator(chip); if (rc < 0) { pr_err("Couldn't initialize vbus regulator rc=%d\n", @@ -1511,25 +1646,71 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } - return rc; + return 0; cleanup: smblib_deinit(chg); - if (chip->parallel_psy) - power_supply_unregister(chip->parallel_psy); - if (chg->vbus_vreg && chg->vbus_vreg->rdev) - regulator_unregister(chg->vbus_vreg->rdev); return rc; } +static int slave_probe(struct smb138x *chip) +{ + struct device_node *revid_dev_node; + int rc = 0; + + revid_dev_node = of_parse_phandle(chip->chg.dev->of_node, + "qcom,pmic-revid", 0); + if (!revid_dev_node) { + pr_err("Missing qcom,pmic-revid property\n"); + return -EINVAL; + } + + chip->pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR_OR_NULL(chip->pmic_rev_id)) { + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + switch (chip->pmic_rev_id->pmic_subtype) { + case SMB1355_SUBTYPE: + chip->name = "smb1355"; + rc = smb1355_slave_probe(chip); + break; + case SMB1381_SUBTYPE: + chip->name = "smb1381"; + rc = smb1381_slave_probe(chip); + break; + default: + pr_err("Unsupported pmic subtype = 0x%02x\n", + chip->pmic_rev_id->pmic_subtype); + rc = -EINVAL; + } + + if (rc < 0) { + if (rc != -EPROBE_DEFER) + pr_err("Couldn't probe SMB138X rc=%d\n", rc); + return rc; + } + + return 0; +} + static const struct of_device_id match_table[] = { { - .compatible = "qcom,smb138x-charger", - .data = (void *) PARALLEL_MASTER + .compatible = "qcom,smb138x-charger", + .data = (void *) PARALLEL_MASTER, + }, + { + .compatible = "qcom,smb138x-parallel-slave", + .data = (void *) PARALLEL_SLAVE, }, { - .compatible = "qcom,smb138x-parallel-slave", - .data = (void *) PARALLEL_SLAVE + .compatible = "qcom,smb1355-parallel-slave", + .data = (void *) PARALLEL_SLAVE, }, { }, }; @@ -1576,7 +1757,7 @@ static int smb138x_probe(struct platform_device *pdev) rc = smb138x_master_probe(chip); break; case PARALLEL_SLAVE: - rc = smb138x_slave_probe(chip); + rc = slave_probe(chip); break; default: pr_err("Couldn't find a matching mode %d\n", chip->chg.mode); @@ -1590,7 +1771,8 @@ static int smb138x_probe(struct platform_device *pdev) goto cleanup; } - pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode); + pr_info("%s probed successfully mode=%d pl_mode = %d\n", + chip->name, chip->chg.mode, chip->dt.pl_mode); return rc; cleanup: diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 333ad7d5b45b..da72b0b59c3a 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -57,7 +57,7 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) int rising_edge; /* Get the time stamp first */ - pps_get_ts(&ts); + get_monotonic_boottime(&ts.ts_real); info = data; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d5c00951cf93..5d81bcc1dc75 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2806,10 +2806,10 @@ static int sd_revalidate_disk(struct gendisk *disk) if (sdkp->opt_xfer_blocks && sdkp->opt_xfer_blocks <= dev_max && sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS && - logical_to_bytes(sdp, sdkp->opt_xfer_blocks) >= PAGE_CACHE_SIZE) { - q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks); - rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks); - } else + sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE) + rw_max = q->limits.io_opt = + sdkp->opt_xfer_blocks * sdp->sector_size; + else rw_max = BLK_DEF_MAX_SECTORS; /* Combine with controller limits */ diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 765a6f1ac1b7..654630bb7d0e 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -151,11 +151,6 @@ static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blo return blocks << (ilog2(sdev->sector_size) - 9); } -static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t blocks) -{ - return blocks * sdev->sector_size; -} - /* * A DIF-capable target device can be formatted with different * protection schemes. Currently 0 through 3 are defined: diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3e858015813f..79bb3337ba36 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4289,15 +4289,25 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) * mode hence full reinit is required to move link to HS speeds. */ if (ret || hba->full_init_linereset) { + int err; + hba->full_init_linereset = false; ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER); dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d", __func__, ret); /* - * If link recovery fails then return error so that caller - * don't retry the hibern8 enter again. + * If link recovery fails then return error code (-ENOLINK) + * returned ufshcd_link_recovery(). + * If link recovery succeeds then return -EAGAIN to attempt + * hibern8 enter retry again. */ - ret = ufshcd_link_recovery(hba); + err = ufshcd_link_recovery(hba); + if (err) { + dev_err(hba->dev, "%s: link recovery failed", __func__); + ret = err; + } else { + ret = -EAGAIN; + } } else { dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__, ktime_to_us(ktime_get())); @@ -4314,8 +4324,8 @@ int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) ret = __ufshcd_uic_hibern8_enter(hba); if (!ret) goto out; - /* Unable to recover the link, so no point proceeding */ - if (ret == -ENOLINK) + else if (ret != -EAGAIN) + /* Unable to recover the link, so no point proceeding */ BUG(); } out: diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index cc809cbdd839..72f5829d1eb6 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -1845,7 +1845,7 @@ static void glink_ch_ctx_release(struct rwref_lock *ch_st_lock) /** * ch_name_to_ch_ctx_create() - lookup a channel by name, create the channel if - * it is not found. + * it is not found and get reference of context. * @xprt_ctx: Transport to search for a matching channel. * @name: Name of the desired channel. * @@ -1901,6 +1901,7 @@ check_ctx: spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1, flags); kfree(ctx); + rwref_get(&entry->ch_state_lhb2); rwref_write_put(&xprt_ctx->xprt_state_lhb0); return entry; } @@ -1935,6 +1936,7 @@ check_ctx: "%s: local:GLINK_CHANNEL_CLOSED\n", __func__); } + rwref_get(&ctx->ch_state_lhb2); spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1, flags); rwref_write_put(&xprt_ctx->xprt_state_lhb0); mutex_lock(&xprt_ctx->xprt_dbgfs_lock_lhb4); @@ -2579,6 +2581,7 @@ void *glink_open(const struct glink_open_config *cfg) GLINK_INFO_CH_XPRT(ctx, transport_ptr, "%s: Channel not ready to be re-opened. State: %u\n", __func__, ctx->local_open_state); + rwref_put(&ctx->ch_state_lhb2); return ERR_PTR(-EBUSY); } @@ -2627,11 +2630,13 @@ void *glink_open(const struct glink_open_config *cfg) ctx->local_open_state = GLINK_CHANNEL_CLOSED; GLINK_ERR_CH(ctx, "%s: Unable to send open command %d\n", __func__, ret); + rwref_put(&ctx->ch_state_lhb2); return ERR_PTR(ret); } GLINK_INFO_CH(ctx, "%s: Created channel, sent OPEN command. ctx %p\n", __func__, ctx); + rwref_put(&ctx->ch_state_lhb2); return ctx; } EXPORT_SYMBOL(glink_open); @@ -4804,6 +4809,7 @@ static void glink_core_rx_cmd_ch_remote_open(struct glink_transport_if *if_ptr, GLINK_ERR_CH(ctx, "%s: Duplicate remote open for rcid %u, name '%s'\n", __func__, rcid, name); + rwref_put(&ctx->ch_state_lhb2); glink_core_migration_edge_unlock(if_ptr->glink_core_priv); return; } @@ -4826,6 +4832,7 @@ static void glink_core_rx_cmd_ch_remote_open(struct glink_transport_if *if_ptr, if (do_migrate) ch_migrate(NULL, ctx); + rwref_put(&ctx->ch_state_lhb2); glink_core_migration_edge_unlock(if_ptr->glink_core_priv); } diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 2dc4208cbc51..85d51807077c 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -798,6 +798,12 @@ static bool get_rx_fifo(struct edge_info *einfo) einfo->remote_proc_id, SMEM_ITEM_CACHED_FLAG); if (!einfo->rx_fifo) + einfo->rx_fifo = smem_get_entry( + SMEM_GLINK_NATIVE_XPRT_FIFO_1, + &einfo->rx_fifo_size, + einfo->remote_proc_id, + 0); + if (!einfo->rx_fifo) return false; } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 0b35caa86d51..ab46eb70651c 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -2110,7 +2110,6 @@ static int icnss_driver_event_register_driver(void *data) power_off: icnss_hw_power_off(penv); - penv->ops = NULL; out: return ret; } @@ -2646,7 +2645,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops) } ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER, - ICNSS_EVENT_SYNC, ops); + 0, ops); if (ret == -EINTR) ret = 0; diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index 78f6a2aa8f66..a92e5c416678 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -625,14 +625,17 @@ ssize_t glink_pkt_read(struct file *file, return -ENETRESET; } + mutex_lock(&devp->ch_lock); if (!glink_rx_intent_exists(devp->handle, count)) { ret = glink_queue_rx_intent(devp->handle, devp, count); if (ret) { GLINK_PKT_ERR("%s: failed to queue_rx_intent ret[%d]\n", __func__, ret); + mutex_unlock(&devp->ch_lock); return ret; } } + mutex_unlock(&devp->ch_lock); GLINK_PKT_INFO("Begin %s on glink_pkt_dev id:%d buffer_size %zu\n", __func__, devp->i, count); diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 6f75eee8f921..8efe18dcc98f 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -45,6 +45,8 @@ #include <linux/msm-bus-board.h> #include "spi_qsd.h" +#define SPI_MAX_BYTES_PER_WORD (4) + static int msm_spi_pm_resume_runtime(struct device *device); static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); @@ -438,10 +440,12 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) u32 data_in; int i; int shift; + int read_bytes = (dd->pack_words ? + SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO); if (dd->read_buf) { - for (i = 0; (i < dd->bytes_per_word) && + for (i = 0; (i < read_bytes) && dd->rx_bytes_remaining; i++) { /* The data format depends on bytes_per_word: 4 bytes: 0x12345678 @@ -454,8 +458,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) dd->rx_bytes_remaining--; } } else { - if (dd->rx_bytes_remaining >= dd->bytes_per_word) - dd->rx_bytes_remaining -= dd->bytes_per_word; + if (dd->rx_bytes_remaining >= read_bytes) + dd->rx_bytes_remaining -= read_bytes; else dd->rx_bytes_remaining = 0; } @@ -552,7 +556,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n) if (n != (*config & SPI_CFG_N)) *config = (*config & ~SPI_CFG_N) | n; - if (dd->mode == SPI_BAM_MODE) { + if (dd->tx_mode == SPI_BAM_MODE) { if (dd->read_buf == NULL) *config |= SPI_NO_INPUT; if (dd->write_buf == NULL) @@ -617,25 +621,34 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw) static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words) { /* - * n_words cannot exceed fifo_size, and only one READ COUNT - * interrupt is generated per transaction, so for transactions - * larger than fifo size READ COUNT must be disabled. - * For those transactions we usually move to Data Mover mode. + * For FIFO mode: + * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0 + * - Set the READ/WRITE_COUNT registers to 0 (infinite mode) + * or num bytes (finite mode) if less than fifo worth of data. + * For Block mode: + * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes. + * - Set the READ/WRITE_COUNT registers to 0. */ - if (dd->mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) { - writel_relaxed(n_words, - dd->base + SPI_MX_READ_COUNT); - msm_spi_set_write_count(dd, n_words); - } else { - writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); - msm_spi_set_write_count(dd, 0); - } - if (dd->qup_ver == SPI_QUP_VERSION_BFAM) { - /* must be zero for FIFO */ - writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); + if (dd->tx_mode != SPI_BAM_MODE) { + if (dd->tx_mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) + msm_spi_set_write_count(dd, n_words); + else + msm_spi_set_write_count(dd, 0); writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); - } + } else + writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT); + + if (dd->rx_mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) + writel_relaxed(n_words, + dd->base + SPI_MX_READ_COUNT); + else + writel_relaxed(0, + dd->base + SPI_MX_READ_COUNT); + writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); + } else + writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT); } else { /* must be zero for BAM and DMOV */ writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); @@ -882,7 +895,7 @@ xfr_err: static int msm_spi_bam_next_transfer(struct msm_spi *dd) { - if (dd->mode != SPI_BAM_MODE) + if (dd->tx_mode != SPI_BAM_MODE) return 0; if (dd->tx_bytes_remaining > 0) { @@ -901,7 +914,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd) static int msm_spi_dma_send_next(struct msm_spi *dd) { int ret = 0; - if (dd->mode == SPI_BAM_MODE) + if (dd->tx_mode == SPI_BAM_MODE) ret = msm_spi_bam_next_transfer(dd); return ret; } @@ -932,32 +945,38 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); + writel_relaxed(op, dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); if (op & SPI_OP_INPUT_SERVICE_FLAG) { - writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG, - dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); ret |= msm_spi_input_irq(irq, dev_id); } if (op & SPI_OP_OUTPUT_SERVICE_FLAG) { - writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG, - dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); ret |= msm_spi_output_irq(irq, dev_id); } - if (dd->done) { + if (dd->tx_mode != SPI_BAM_MODE) { + if (!dd->rx_done) { + if (dd->rx_bytes_remaining == 0) + dd->rx_done = true; + } + if (!dd->tx_done) { + if (!dd->tx_bytes_remaining && + (op & SPI_OP_IP_FIFO_NOT_EMPTY)) { + dd->tx_done = true; + } + } + } + if (dd->tx_done && dd->rx_done) { + msm_spi_set_state(dd, SPI_OP_STATE_RESET); + dd->tx_done = false; + dd->rx_done = false; complete(&dd->rx_transfer_complete); complete(&dd->tx_transfer_complete); - dd->done = 0; } return ret; } @@ -968,17 +987,23 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id) dd->stat_rx++; - if (dd->mode == SPI_MODE_NONE) + if (dd->rx_mode == SPI_MODE_NONE) return IRQ_HANDLED; - if (dd->mode == SPI_FIFO_MODE) { + if (dd->rx_mode == SPI_FIFO_MODE) { while ((readl_relaxed(dd->base + SPI_OPERATIONAL) & SPI_OP_IP_FIFO_NOT_EMPTY) && (dd->rx_bytes_remaining > 0)) { msm_spi_read_word_from_fifo(dd); } - if (dd->rx_bytes_remaining == 0) - msm_spi_complete(dd); + } else if (dd->rx_mode == SPI_BLOCK_MODE) { + int count = 0; + + while (dd->rx_bytes_remaining && + (count < dd->input_block_size)) { + msm_spi_read_word_from_fifo(dd); + count += SPI_MAX_BYTES_PER_WORD; + } } return IRQ_HANDLED; @@ -989,18 +1014,20 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd) u32 word; u8 byte; int i; + int write_bytes = + (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); word = 0; if (dd->write_buf) { - for (i = 0; (i < dd->bytes_per_word) && + for (i = 0; (i < write_bytes) && dd->tx_bytes_remaining; i++) { dd->tx_bytes_remaining--; byte = *dd->write_buf++; word |= (byte << (BITS_PER_BYTE * i)); } } else - if (dd->tx_bytes_remaining > dd->bytes_per_word) - dd->tx_bytes_remaining -= dd->bytes_per_word; + if (dd->tx_bytes_remaining > write_bytes) + dd->tx_bytes_remaining -= write_bytes; else dd->tx_bytes_remaining = 0; dd->write_xfr_cnt++; @@ -1012,11 +1039,22 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd) { int count = 0; - while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) && - !(readl_relaxed(dd->base + SPI_OPERATIONAL) & - SPI_OP_OUTPUT_FIFO_FULL)) { - msm_spi_write_word_to_fifo(dd); - count++; + if (dd->tx_mode == SPI_FIFO_MODE) { + while ((dd->tx_bytes_remaining > 0) && + (count < dd->input_fifo_size) && + !(readl_relaxed(dd->base + SPI_OPERATIONAL) + & SPI_OP_OUTPUT_FIFO_FULL)) { + msm_spi_write_word_to_fifo(dd); + count++; + } + } + + if (dd->tx_mode == SPI_BLOCK_MODE) { + while (dd->tx_bytes_remaining && + (count < dd->output_block_size)) { + msm_spi_write_word_to_fifo(dd); + count += SPI_MAX_BYTES_PER_WORD; + } } } @@ -1026,11 +1064,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id) dd->stat_tx++; - if (dd->mode == SPI_MODE_NONE) + if (dd->tx_mode == SPI_MODE_NONE) return IRQ_HANDLED; /* Output FIFO is empty. Transmit any outstanding write data. */ - if (dd->mode == SPI_FIFO_MODE) + if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE)) msm_spi_write_rmn_to_fifo(dd); return IRQ_HANDLED; @@ -1106,7 +1144,7 @@ error: static int msm_spi_dma_map_buffers(struct msm_spi *dd) { int ret = 0; - if (dd->mode == SPI_BAM_MODE) + if (dd->tx_mode == SPI_BAM_MODE) ret = msm_spi_bam_map_buffers(dd); return ret; } @@ -1135,7 +1173,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd) static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd) { - if (dd->mode == SPI_BAM_MODE) + if (dd->tx_mode == SPI_BAM_MODE) msm_spi_bam_unmap_buffers(dd); } @@ -1197,9 +1235,11 @@ static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { - dd->mode = SPI_BAM_MODE; + dd->tx_mode = SPI_BAM_MODE; + dd->rx_mode = SPI_BAM_MODE; } else { - dd->mode = SPI_FIFO_MODE; + dd->rx_mode = SPI_FIFO_MODE; + dd->tx_mode = SPI_FIFO_MODE; dd->read_len = dd->cur_transfer->len; dd->write_len = dd->cur_transfer->len; } @@ -1215,14 +1255,23 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd) spi_iom = readl_relaxed(dd->base + SPI_IO_MODES); /* Set input and output transfer mode: FIFO, DMOV, or BAM */ spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE); - spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT)); - spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT)); - /* Turn on packing for data mover */ - if (dd->mode == SPI_BAM_MODE) + spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT)); + spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT)); + + /* Always enable packing for the BAM mode and for non BAM mode only + * if bpw is % 8 and transfer length is % 4 Bytes. + */ + if (dd->tx_mode == SPI_BAM_MODE || + ((dd->cur_msg_len % SPI_MAX_BYTES_PER_WORD == 0) && + (dd->cur_transfer->bits_per_word) && + (dd->cur_transfer->bits_per_word <= 32) && + (dd->cur_transfer->bits_per_word % 8 == 0))) { spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN; - else { + dd->pack_words = true; + } else { spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN); spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN; + dd->pack_words = false; } /*if (dd->mode == SPI_BAM_MODE) { @@ -1280,7 +1329,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd) { /* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status * change in BAM mode */ - u32 mask = (dd->mode == SPI_BAM_MODE) ? + u32 mask = (dd->tx_mode == SPI_BAM_MODE) ? QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG : 0; writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK); @@ -1321,6 +1370,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd) dd->rx_bytes_remaining = dd->cur_msg_len; dd->read_buf = dd->cur_transfer->rx_buf; dd->write_buf = dd->cur_transfer->tx_buf; + dd->tx_done = false; + dd->rx_done = false; init_completion(&dd->tx_transfer_complete); init_completion(&dd->rx_transfer_complete); if (dd->cur_transfer->bits_per_word) @@ -1351,10 +1402,12 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_transfer_mode(dd, bpw, read_count); msm_spi_set_mx_counts(dd, read_count); - if (dd->mode == SPI_BAM_MODE) { + if (dd->tx_mode == SPI_BAM_MODE) { ret = msm_spi_dma_map_buffers(dd); if (ret < 0) { pr_err("Mapping DMA buffers\n"); + dd->tx_mode = SPI_MODE_NONE; + dd->rx_mode = SPI_MODE_NONE; return ret; } } @@ -1368,11 +1421,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) the first. Restricting this to one write avoids contention issues and race conditions between this thread and the int handler */ - if (dd->mode == SPI_FIFO_MODE) { + if (dd->tx_mode != SPI_BAM_MODE) { if (msm_spi_prepare_for_write(dd)) goto transfer_end; msm_spi_start_write(dd, read_count); - } else if (dd->mode == SPI_BAM_MODE) { + } else { if ((msm_spi_bam_begin_transfer(dd)) < 0) { dev_err(dd->dev, "%s: BAM transfer setup failed\n", __func__); @@ -1388,11 +1441,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) * might fire before the first word is written resulting in a * possible race condition. */ - if (dd->mode != SPI_BAM_MODE) + if (dd->tx_mode != SPI_BAM_MODE) if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) { dev_warn(dd->dev, "%s: Failed to set QUP to run-state. Mode:%d", - __func__, dd->mode); + __func__, dd->tx_mode); goto transfer_end; } @@ -1422,10 +1475,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_udelay(dd->xfrs_delay_usec); transfer_end: - if ((dd->mode == SPI_BAM_MODE) && status) + if ((dd->tx_mode == SPI_BAM_MODE) && status) msm_spi_bam_flush(dd); msm_spi_dma_unmap_buffers(dd); - dd->mode = SPI_MODE_NONE; + dd->tx_mode = SPI_MODE_NONE; + dd->rx_mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); if (!dd->cur_transfer->cs_change) @@ -2349,7 +2403,8 @@ static int init_resources(struct platform_device *pdev) pclk_enabled = 0; dd->transfer_pending = 0; - dd->mode = SPI_MODE_NONE; + dd->tx_mode = SPI_MODE_NONE; + dd->rx_mode = SPI_MODE_NONE; rc = msm_spi_request_irq(dd, pdev, master); if (rc) diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index 7a5cfadaa5a0..47d69965f18a 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.h @@ -113,6 +113,8 @@ #define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12) /* SPI_OPERATIONAL fields */ +#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000 +#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000 #define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800 #define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400 #define SPI_OP_INPUT_SERVICE_FLAG 0x00000200 @@ -321,7 +323,8 @@ struct msm_spi { bool transfer_pending; wait_queue_head_t continue_suspend; /* DMA data */ - enum msm_spi_mode mode; + enum msm_spi_mode tx_mode; + enum msm_spi_mode rx_mode; bool use_dma; int tx_dma_chan; int tx_dma_crci; @@ -353,7 +356,8 @@ struct msm_spi { #endif struct msm_spi_platform_data *pdata; /* Platform data */ /* When set indicates multiple transfers in a single message */ - bool done; + bool rx_done; + bool tx_done; u32 cur_msg_len; /* Used in FIFO mode to keep track of the transfer being processed */ struct spi_transfer *cur_tx_transfer; @@ -371,6 +375,7 @@ struct msm_spi { struct pinctrl_state *pins_active; struct pinctrl_state *pins_sleep; bool is_init_complete; + bool pack_words; }; /* Forward declaration */ @@ -524,7 +529,8 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) static inline void msm_spi_complete(struct msm_spi *dd) { - dd->done = 1; + dd->tx_done = true; + dd->rx_done = true; } static inline void msm_spi_enable_error_flags(struct msm_spi *dd) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index b5905fc81147..dfb6d2f77af1 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -238,7 +238,7 @@ void ion_cma_heap_destroy(struct ion_heap *heap) static void ion_secure_cma_free(struct ion_buffer *buffer) { int ret = 0; - u32 source_vm; + int source_vm; int dest_vmid; int dest_perms; struct ion_cma_buffer_info *info = buffer->priv_virt; diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index ec09f9f12b47..803811597f37 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-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -78,7 +78,7 @@ int ion_system_secure_heap_unassign_sg(struct sg_table *sgt, int source_vmid) int ion_system_secure_heap_assign_sg(struct sg_table *sgt, int dest_vmid) { - u32 source_vmid = VMID_HLOS; + int source_vmid = VMID_HLOS; u32 dest_perms = PERM_READ | PERM_WRITE; struct scatterlist *sg; int ret, i; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index be532503954f..7216fdd4245d 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1550,13 +1550,6 @@ static void gsi_ctrl_notify_resp_complete(struct usb_ep *ep, event->bNotificationType, req->status); /* FALLTHROUGH */ case 0: - /* - * handle multiple pending resp available - * notifications by queuing same until we're done, - * rest of the notification require queuing new - * request. - */ - gsi_ctrl_send_notification(gsi); break; } } @@ -1651,6 +1644,14 @@ static void gsi_ctrl_reset_cmd_complete(struct usb_ep *ep, gsi_ctrl_send_cpkt_tomodem(gsi, req->buf, 0); } +static void gsi_ctrl_send_response_complete(struct usb_ep *ep, + struct usb_request *req) +{ + struct f_gsi *gsi = req->context; + + gsi_ctrl_send_notification(gsi); +} + static int gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -1737,6 +1738,8 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) memcpy(req->buf, cpkt->buf, value); gsi_ctrl_pkt_free(cpkt); + req->complete = gsi_ctrl_send_response_complete; + req->context = gsi; log_event_dbg("copied encap_resp %d bytes", value); break; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 1fd5a95b6e99..59d6ac67d072 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2284,16 +2284,15 @@ reset: fsg->bulk_out_enabled = 0; } + /* allow usb LPM after eps are disabled */ + usb_gadget_autopm_put_async(common->gadget); common->fsg = NULL; wake_up(&common->fsg_wait); } common->running = 0; - if (!new_fsg || rc) { - /* allow usb LPM after eps are disabled */ - usb_gadget_autopm_put_async(common->gadget); + if (!new_fsg || rc) return rc; - } common->fsg = new_fsg; fsg = common->fsg; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 452c0b0d2f32..d8f4316167d8 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1535,6 +1535,9 @@ struct ieee80211_vht_operation { #define WLAN_AUTH_SHARED_KEY 1 #define WLAN_AUTH_FT 2 #define WLAN_AUTH_SAE 3 +#define WLAN_AUTH_FILS_SK 4 +#define WLAN_AUTH_FILS_SK_PFS 5 +#define WLAN_AUTH_FILS_PK 6 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h index 2b50ce59406e..c01cb1af4231 100644 --- a/include/linux/msm_mhi.h +++ b/include/linux/msm_mhi.h @@ -62,7 +62,9 @@ enum MHI_CLIENT_CHANNEL { MHI_CLIENT_CSVT_IN = 43, MHI_CLIENT_SMCT_OUT = 44, MHI_CLIENT_SMCT_IN = 45, - MHI_CLIENT_RESERVED_1_LOWER = 46, + MHI_CLIENT_IP_SW_4_OUT = 46, + MHI_CLIENT_IP_SW_4_IN = 47, + MHI_CLIENT_RESERVED_1_LOWER = 48, MHI_CLIENT_RESERVED_1_UPPER = 99, MHI_CLIENT_IP_HW_0_OUT = 100, MHI_CLIENT_IP_HW_0_IN = 101, diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h index 7254f4d16176..7fca674b6230 100644 --- a/include/linux/qpnp/qpnp-revid.h +++ b/include/linux/qpnp/qpnp-revid.h @@ -235,6 +235,9 @@ /* SMB1381 */ #define SMB1381_SUBTYPE 0x17 +/* SMB1355 */ +#define SMB1355_SUBTYPE 0x1C + struct pmic_revid_data { u8 rev1; u8 rev2; diff --git a/include/linux/sched.h b/include/linux/sched.h index 95d758d63784..4b56a62a0a58 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -3247,6 +3247,15 @@ static inline void cond_resched_rcu(void) #endif } +static inline unsigned long get_preempt_disable_ip(struct task_struct *p) +{ +#ifdef CONFIG_DEBUG_PREEMPT + return p->preempt_disable_ip; +#else + return 0; +#endif +} + /* * Does a critical section need to be broken due to another * task waiting?: (technically does not depend on CONFIG_PREEMPT, diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h new file mode 100644 index 000000000000..f2322f3c74f7 --- /dev/null +++ b/include/linux/usb/audio-v3.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This file holds USB constants and structures defined + * by the USB Device Class Definition for Audio Devices in version 3.0. + * Comments below reference relevant sections of the documents contained + * in http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip + */ + +#ifndef __LINUX_USB_AUDIO_V3_H +#define __LINUX_USB_AUDIO_V3_H + +#include <linux/types.h> + +#define UAC3_MIXER_UNIT_V3 0x05 +#define UAC3_FEATURE_UNIT_V3 0x07 +#define UAC3_CLOCK_SOURCE 0x0b + +#define BADD_MAXPSIZE_SYNC_MONO_16 0x0060 +#define BADD_MAXPSIZE_SYNC_MONO_24 0x0090 +#define BADD_MAXPSIZE_SYNC_STEREO_16 0x00c0 +#define BADD_MAXPSIZE_SYNC_STEREO_24 0x0120 + +#define BADD_MAXPSIZE_ASYNC_MONO_16 0x0062 +#define BADD_MAXPSIZE_ASYNC_MONO_24 0x0093 +#define BADD_MAXPSIZE_ASYNC_STEREO_16 0x00c4 +#define BADD_MAXPSIZE_ASYNC_STEREO_24 0x0126 + +#define BIT_RES_16_BIT 0x10 +#define BIT_RES_24_BIT 0x18 + +#define SUBSLOTSIZE_16_BIT 0x02 +#define SUBSLOTSIZE_24_BIT 0x03 + +#define BADD_SAMPLING_RATE 48000 + +#define NUM_CHANNELS_MONO 1 +#define NUM_CHANNELS_STEREO 2 +#define BADD_CH_CONFIG_MONO 0 +#define BADD_CH_CONFIG_STEREO 3 +#define CLUSTER_ID_MONO 0x0001 +#define CLUSTER_ID_STEREO 0x0002 + +#define FULL_ADC_PROFILE 0x01 + +/* BADD Profile IDs */ +#define PROF_GENERIC_IO 0x20 +#define PROF_HEADPHONE 0x21 +#define PROF_SPEAKER 0x22 +#define PROF_MICROPHONE 0x23 +#define PROF_HEADSET 0x24 +#define PROF_HEADSET_ADAPTER 0x25 +#define PROF_SPEAKERPHONE 0x26 + +/* BADD Entity IDs */ +#define BADD_OUT_TERM_ID_BAOF 0x03 +#define BADD_OUT_TERM_ID_BAIF 0x06 +#define BADD_IN_TERM_ID_BAOF 0x01 +#define BADD_IN_TERM_ID_BAIF 0x04 +#define BADD_FU_ID_BAOF 0x02 +#define BADD_FU_ID_BAIF 0x05 +#define BADD_CLOCK_SOURCE 0x09 +#define BADD_FU_ID_BAIOF 0x07 +#define BADD_MU_ID_BAIOF 0x08 + +#define UAC_BIDIR_TERMINAL_HEADSET 0x0402 +#define UAC_BIDIR_TERMINAL_SPEAKERPHONE 0x0403 + +#define NUM_BADD_DESCS 7 + +struct uac3_input_terminal_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __u8 bTerminalID; + __u16 wTerminalType; + __u8 bAssocTerminal; + __u8 bCSourceID; + __u32 bmControls; + __u16 wClusterDescrID; + __u16 wExTerminalDescrID; + __u16 wConnectorsDescrID; + __u16 wTerminalDescrStr; +} __packed; + +#define UAC3_DT_INPUT_TERMINAL_SIZE 0x14 + +extern struct uac3_input_terminal_descriptor badd_baif_in_term_desc; +extern struct uac3_input_terminal_descriptor badd_baof_in_term_desc; + +struct uac3_output_terminal_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __u8 bTerminalID; + __u16 wTerminalType; + __u8 bAssocTerminal; + __u8 bSourceID; + __u8 bCSourceID; + __u32 bmControls; + __u16 wExTerminalDescrID; + __u16 wConnectorsDescrID; + __u16 wTerminalDescrStr; +} __packed; + +#define UAC3_DT_OUTPUT_TERMINAL_SIZE 0x13 + +extern struct uac3_output_terminal_descriptor badd_baif_out_term_desc; +extern struct uac3_output_terminal_descriptor badd_baof_out_term_desc; + +extern __u8 monoControls[]; +extern __u8 stereoControls[]; +extern __u8 badd_mu_src_ids[]; + +struct uac3_mixer_unit_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __u8 bUnitID; + __u8 bNrInPins; + __u8 *baSourceID; + __u16 wClusterDescrID; + __u8 bmMixerControls; + __u32 bmControls; + __u16 wMixerDescrStr; +} __packed; + +#define UAC3_DT_MIXER_UNIT_SIZE 0x10 + +extern struct uac3_mixer_unit_descriptor badd_baiof_mu_desc; + +struct uac3_feature_unit_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __u8 bUnitID; + __u8 bSourceID; + __u8 *bmaControls; + __u16 wFeatureDescrStr; +} __packed; + +extern struct uac3_feature_unit_descriptor badd_baif_fu_desc; +extern struct uac3_feature_unit_descriptor badd_baof_fu_desc; +extern struct uac3_feature_unit_descriptor badd_baiof_fu_desc; + +struct uac3_clock_source_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __u8 bClockID; + __u8 bmAttributes; + __u32 bmControls; + __u8 bReferenceTerminal; + __u16 wClockSourceStr; +} __packed; + +#define UAC3_DT_CLOCK_SRC_SIZE 0x0c + +extern struct uac3_clock_source_descriptor badd_clock_desc; + +extern void *badd_desc_list[]; + +#endif /* __LINUX_USB_AUDIO_V3_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 85534884c1a0..e9277e860bd7 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1783,9 +1783,11 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); * @key_len: length of WEP key for shared key authentication * @key_idx: index of WEP key for shared key authentication * @key: WEP key for shared key authentication - * @sae_data: Non-IE data to use with SAE or %NULL. This starts with - * Authentication transaction sequence number field. - * @sae_data_len: Length of sae_data buffer in octets + * @auth_data: Fields and elements in Authentication frames. This contains + * the authentication frame body (non-IE and IE data), excluding the + * Authentication algorithm number, i.e., starting at the Authentication + * transaction sequence number field. + * @auth_data_len: Length of auth_data buffer in octets */ struct cfg80211_auth_request { struct cfg80211_bss *bss; @@ -1794,8 +1796,8 @@ struct cfg80211_auth_request { enum nl80211_auth_type auth_type; const u8 *key; u8 key_len, key_idx; - const u8 *sae_data; - size_t sae_data_len; + const u8 *auth_data; + size_t auth_data_len; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8a5c59a9ff0e..960aa84e3b61 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1637,8 +1637,16 @@ enum nl80211_commands { * the connection request from a station. nl80211_connect_failed_reason * enum has different reasons of connection failure. * - * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts - * with the Authentication transaction sequence number field. + * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames. + * This contains the authentication frame body (non-IE and IE data), + * excluding the Authentication algorithm number, i.e., starting at the + * Authentication transaction sequence number field. It is used with + * authentication algorithms that need special fields to be added into + * the frames (SAE and FILS). Currently, only the SAE cases use the + * initial two fields (Authentication transaction sequence number and + * Status code). However, those fields are included in the attribute data + * for all authentication algorithms to keep the attribute definition + * consistent. * * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from * association request when used with NL80211_CMD_NEW_STATION) @@ -2215,7 +2223,7 @@ enum nl80211_attrs { NL80211_ATTR_CONN_FAILED_REASON, - NL80211_ATTR_SAE_DATA, + NL80211_ATTR_AUTH_DATA, NL80211_ATTR_VHT_CAPABILITY, @@ -2379,6 +2387,7 @@ enum nl80211_attrs { #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG #define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER +#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA /* * Allow user space programs to use #ifdef on new attributes by defining them @@ -3666,6 +3675,9 @@ enum nl80211_bss_status { * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals + * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key + * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS + * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key * @__NL80211_AUTHTYPE_NUM: internal * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by @@ -3678,6 +3690,9 @@ enum nl80211_auth_type { NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_NETWORK_EAP, NL80211_AUTHTYPE_SAE, + NL80211_AUTHTYPE_FILS_SK, + NL80211_AUTHTYPE_FILS_SK_PFS, + NL80211_AUTHTYPE_FILS_PK, /* keep last */ __NL80211_AUTHTYPE_NUM, diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index d2314be4f0c0..c6f5b096c594 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h @@ -26,6 +26,7 @@ /* bInterfaceProtocol values to denote the version of the standard used */ #define UAC_VERSION_1 0x00 #define UAC_VERSION_2 0x20 +#define UAC_VERSION_3 0x30 /* A.2 Audio Interface Subclass Codes */ #define USB_SUBCLASS_AUDIOCONTROL 0x01 diff --git a/kernel/cpu.c b/kernel/cpu.c index 8b6940755e4a..0ca3599cee1f 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -530,9 +530,41 @@ out: return ret; } +static int switch_to_rt_policy(void) +{ + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + unsigned int policy = current->policy; + int err; + + /* Nobody should be attempting hotplug from these policy contexts. */ + if (policy == SCHED_BATCH || policy == SCHED_IDLE || + policy == SCHED_DEADLINE) + return -EPERM; + + if (policy == SCHED_FIFO || policy == SCHED_RR) + return 1; + + /* Only SCHED_NORMAL left. */ + err = sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); + return err; + +} + +static int switch_to_fair_policy(void) +{ + struct sched_param param = { .sched_priority = 0 }; + + return sched_setscheduler_nocheck(current, SCHED_NORMAL, ¶m); +} + int cpu_up(unsigned int cpu) { int err = 0; + int switch_err = 0; + + switch_err = switch_to_rt_policy(); + if (switch_err < 0) + return switch_err; if (!cpu_possible(cpu)) { pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n", @@ -558,6 +590,13 @@ int cpu_up(unsigned int cpu) out: cpu_maps_update_done(); + + if (!switch_err) { + switch_err = switch_to_fair_policy(); + pr_err("Hotplug policy switch err. Task %s pid=%d\n", + current->comm, current->pid); + } + return err; } EXPORT_SYMBOL_GPL(cpu_up); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1017a3f77391..e107c4d6b385 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3364,6 +3364,9 @@ NOKPROBE_SYMBOL(preempt_count_sub); */ static noinline void __schedule_bug(struct task_struct *prev) { + /* Save this before calling printk(), since that will clobber it */ + unsigned long preempt_disable_ip = get_preempt_disable_ip(current); + if (oops_in_progress) return; @@ -3374,13 +3377,12 @@ static noinline void __schedule_bug(struct task_struct *prev) print_modules(); if (irqs_disabled()) print_irqtrace_events(prev); -#ifdef CONFIG_DEBUG_PREEMPT - if (in_atomic_preempt_off()) { + if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) + && in_atomic_preempt_off()) { pr_err("Preemption disabled at:"); - print_ip_sym(current->preempt_disable_ip); + print_ip_sym(preempt_disable_ip); pr_cont("\n"); } -#endif #ifdef CONFIG_PANIC_ON_SCHED_BUG BUG(); #endif @@ -8513,6 +8515,7 @@ EXPORT_SYMBOL(__might_sleep); void ___might_sleep(const char *file, int line, int preempt_offset) { static unsigned long prev_jiffy; /* ratelimiting */ + unsigned long preempt_disable_ip; rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */ if ((preempt_count_equals(preempt_offset) && !irqs_disabled() && @@ -8525,6 +8528,9 @@ void ___might_sleep(const char *file, int line, int preempt_offset) return; prev_jiffy = jiffies; + /* Save this before calling printk(), since that will clobber it */ + preempt_disable_ip = get_preempt_disable_ip(current); + printk(KERN_ERR "BUG: sleeping function called from invalid context at %s:%d\n", file, line); @@ -8539,13 +8545,12 @@ void ___might_sleep(const char *file, int line, int preempt_offset) debug_show_held_locks(current); if (irqs_disabled()) print_irqtrace_events(current); -#ifdef CONFIG_DEBUG_PREEMPT - if (!preempt_count_equals(preempt_offset)) { + if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) + && !preempt_count_equals(preempt_offset)) { pr_err("Preemption disabled at:"); - print_ip_sym(current->preempt_disable_ip); + print_ip_sym(preempt_disable_ip); pr_cont("\n"); } -#endif #ifdef CONFIG_PANIC_ON_SCHED_BUG BUG(); #endif diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 66d9e907aa07..c0c10a335b3b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1634,7 +1634,7 @@ static void __trace_find_cmdline(int pid, char comm[]) map = savedcmd->map_pid_to_cmdline[pid]; if (map != NO_CMDLINE_MAP) - strcpy(comm, get_saved_cmdlines(map)); + strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN - 1); else strcpy(comm, "<...>"); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 83ddc8074e55..add152e8352c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3200,6 +3200,10 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) { struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; int prefix; + struct net *net = arg->net; + + if (rt == net->ipv6.ip6_null_entry) + return 0; if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); @@ -3207,7 +3211,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) } else prefix = 0; - return rt6_fill_node(arg->net, + return rt6_fill_node(net, arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq, prefix, 0, NLM_F_MULTI); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 23095d5e0199..f3deee7da389 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4490,20 +4490,20 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; } - auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len + + auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len + req->ie_len, GFP_KERNEL); if (!auth_data) return -ENOMEM; auth_data->bss = req->bss; - if (req->sae_data_len >= 4) { - __le16 *pos = (__le16 *) req->sae_data; + if (req->auth_data_len >= 4) { + __le16 *pos = (__le16 *) req->auth_data; auth_data->sae_trans = le16_to_cpu(pos[0]); auth_data->sae_status = le16_to_cpu(pos[1]); - memcpy(auth_data->data, req->sae_data + 4, - req->sae_data_len - 4); - auth_data->data_len += req->sae_data_len - 4; + memcpy(auth_data->data, req->auth_data + 4, + req->auth_data_len - 4); + auth_data->data_len += req->auth_data_len - 4; } if (req->ie && req->ie_len) { diff --git a/net/wireless/core.h b/net/wireless/core.h index 54865316358e..5cfe6fd72d52 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -335,7 +335,7 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, const u8 *key, int key_len, int key_idx, - const u8 *sae_data, int sae_data_len); + const u8 *auth_data, int auth_data_len); int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1b97f978ccd6..e2b1333cc4e4 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -217,14 +217,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, const u8 *key, int key_len, int key_idx, - const u8 *sae_data, int sae_data_len) + const u8 *auth_data, int auth_data_len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req = { .ie = ie, .ie_len = ie_len, - .sae_data = sae_data, - .sae_data_len = sae_data_len, + .auth_data = auth_data, + .auth_data_len = auth_data_len, .auth_type = auth_type, .key = key, .key_len = key_len, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 58b45366c42c..adc62ec5507a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -354,7 +354,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, - [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, + [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, }, [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, @@ -3661,12 +3661,23 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) && auth_type == NL80211_AUTHTYPE_SAE) return false; + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_FILS_STA) && + (auth_type == NL80211_AUTHTYPE_FILS_SK || + auth_type == NL80211_AUTHTYPE_FILS_SK_PFS || + auth_type == NL80211_AUTHTYPE_FILS_PK)) + return false; return true; case NL80211_CMD_CONNECT: case NL80211_CMD_START_AP: /* SAE not supported yet */ if (auth_type == NL80211_AUTHTYPE_SAE) return false; + /* FILS not supported yet */ + if (auth_type == NL80211_AUTHTYPE_FILS_SK || + auth_type == NL80211_AUTHTYPE_FILS_SK_PFS || + auth_type == NL80211_AUTHTYPE_FILS_PK) + return false; return true; default: return false; @@ -7489,8 +7500,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; - const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL; - int err, ssid_len, ie_len = 0, sae_data_len = 0; + const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL; + int err, ssid_len, ie_len = 0, auth_data_len = 0; enum nl80211_auth_type auth_type; struct key_parse key; bool local_state_change; @@ -7569,17 +7580,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE)) return -EINVAL; - if (auth_type == NL80211_AUTHTYPE_SAE && - !info->attrs[NL80211_ATTR_SAE_DATA]) + if ((auth_type == NL80211_AUTHTYPE_SAE || + auth_type == NL80211_AUTHTYPE_FILS_SK || + auth_type == NL80211_AUTHTYPE_FILS_SK_PFS || + auth_type == NL80211_AUTHTYPE_FILS_PK) && + !info->attrs[NL80211_ATTR_AUTH_DATA]) return -EINVAL; - if (info->attrs[NL80211_ATTR_SAE_DATA]) { - if (auth_type != NL80211_AUTHTYPE_SAE) + if (info->attrs[NL80211_ATTR_AUTH_DATA]) { + if (auth_type != NL80211_AUTHTYPE_SAE && + auth_type != NL80211_AUTHTYPE_FILS_SK && + auth_type != NL80211_AUTHTYPE_FILS_SK_PFS && + auth_type != NL80211_AUTHTYPE_FILS_PK) return -EINVAL; - sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]); - sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]); + auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]); + auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]); /* need to include at least Auth Transaction and Status Code */ - if (sae_data_len < 4) + if (auth_data_len < 4) return -EINVAL; } @@ -7596,7 +7613,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, key.p.key, key.p.key_len, key.idx, - sae_data, sae_data_len); + auth_data, auth_data_len); wdev_unlock(dev->ieee80211_ptr); return err; } diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 01df30af4d4a..45473ca4290c 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -64,6 +64,11 @@ ifneq ($(hostprogs-y)$(hostprogs-m),) include scripts/Makefile.host endif +# Do not include host rules unless needed +ifneq ($(dtbo-y),) +include scripts/Makefile.dtbo +endif + ifneq ($(KBUILD_SRC),) # Create output directory if not already present _dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) diff --git a/scripts/Makefile.dtbo b/scripts/Makefile.dtbo new file mode 100644 index 000000000000..db4a0f4b9a56 --- /dev/null +++ b/scripts/Makefile.dtbo @@ -0,0 +1,24 @@ +__dtbo := $(sort $(dtbo-y)) + +dtbo-base := $(sort $(foreach m,$(__dtbo),$($(m)-base))) +dtbo := $(foreach m,$(__dtbo),$(if $($(m)-base),$(m))) + +__dtbo := $(addprefix $(obj)/,$(__dtbo)) +dtbo-base := $(addprefix $(obj)/,$(dtbo-base)) +dtbo := $(addprefix $(obj)/,$(dtbo)) + +ifneq ($(DTC_OVERLAY_TEST_EXT),) +DTC_OVERLAY_TEST = $(DTC_OVERLAY_TEST_EXT) +quiet_cmd_dtbo_verify = VERIFY $@ +cmd_dtbo_verify = $(DTC_OVERLAY_TEST) $(addprefix $(obj)/,$($(@F)-base)) $@ $(dot-target).dtb +else +cmd_dtbo_verify = true +endif + +$(obj)/%.dtbo: $(src)/%.dts FORCE + $(call if_changed_dep,dtc) + $(call if_changed,dtbo_verify) + +$(call multi_depend, $(dtbo), , -base) + +always += $(dtbo) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 861a2acd8cba..46881f329561 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -287,10 +287,16 @@ cmd_dt_S_dtb= \ $(obj)/%.dtb.S: $(obj)/%.dtb $(call cmd,dt_S_dtb) +ifneq ($(DTC_EXT),) +DTC = $(DTC_EXT) +else +DTC = $(objtree)/scripts/dtc/dtc +endif + quiet_cmd_dtc = DTC $@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ - $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \ + $(DTC) -O dtb -o $@ -b 0 \ -i $(dir $<) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) ; \ cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 2a48022c41e7..2eb4aec040f4 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -1,7 +1,9 @@ # scripts/dtc makefile hostprogs-y := dtc +ifeq ($(DTC_EXT),) always := $(hostprogs-y) +endif dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ srcpos.o checks.o util.o diff --git a/security/pfe/pfk_ecryptfs.c b/security/pfe/pfk_ecryptfs.c index f98d85ab4841..f55ee83c30ed 100644 --- a/security/pfe/pfk_ecryptfs.c +++ b/security/pfe/pfk_ecryptfs.c @@ -112,7 +112,7 @@ static int __init pfk_ecryptfs_lsm_init(void) /* * pfk_ecryptfs_deinit() - Deinit function, should be invoked by upper PFK layer */ -void __exit pfk_ecryptfs_deinit(void) +void pfk_ecryptfs_deinit(void) { pfk_ecryptfs_ready = false; ecryptfs_unregister_from_events(g_events_handle); diff --git a/security/pfe/pfk_ecryptfs.h b/security/pfe/pfk_ecryptfs.h index 1d9942c4c09b..bd3a8f2800b8 100644 --- a/security/pfe/pfk_ecryptfs.h +++ b/security/pfe/pfk_ecryptfs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -34,6 +34,6 @@ bool pfk_ecryptfs_allow_merge_bio(const struct bio *bio1, int __init pfk_ecryptfs_init(void); -void __exit pfk_ecryptfs_deinit(void); +void pfk_ecryptfs_deinit(void); #endif /* _PFK_ECRYPTFS_H_ */ diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c index 07e2c7ab829c..b9df18f9fb01 100644 --- a/security/pfe/pfk_ext4.c +++ b/security/pfe/pfk_ext4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,7 +44,7 @@ static bool pfk_ext4_ready; /* * pfk_ext4_deinit() - Deinit function, should be invoked by upper PFK layer */ -void __exit pfk_ext4_deinit(void) +void pfk_ext4_deinit(void) { pfk_ext4_ready = false; } diff --git a/security/pfe/pfk_ext4.h b/security/pfe/pfk_ext4.h index 6b367b428e50..1f336325f1db 100644 --- a/security/pfe/pfk_ext4.h +++ b/security/pfe/pfk_ext4.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,6 +32,6 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1, int __init pfk_ext4_init(void); -void __exit pfk_ext4_deinit(void); +void pfk_ext4_deinit(void); #endif /* _PFK_EXT4_H_ */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index d533984558f0..a2b7fb7a3bca 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -192,7 +192,7 @@ module_param(sido_buck_svs_voltage, int, MODULE_PARM_DESC(sido_buck_svs_voltage, "setting for SVS voltage for SIDO BUCK"); -#define TASHA_TX_UNMUTE_DELAY_MS 25 +#define TASHA_TX_UNMUTE_DELAY_MS 40 static int tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS; module_param(tx_unmute_delay, int, diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index cc8e45d77fcd..e502d6340ffb 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -507,7 +507,7 @@ static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); -#define WCD934X_TX_UNMUTE_DELAY_MS 25 +#define WCD934X_TX_UNMUTE_DELAY_MS 40 static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS; module_param(tx_unmute_delay, int, @@ -9076,8 +9076,9 @@ static int tavil_device_down(struct wcd9xxx *wcd9xxx) codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv); priv = snd_soc_codec_get_drvdata(codec); - swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev, - SWR_DEVICE_DOWN, NULL); + if (priv->swr.ctrl_data) + swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev, + SWR_DEVICE_DOWN, NULL); tavil_dsd_reset(priv->dsd_config); snd_soc_card_change_online_state(codec->component.card, 0); for (count = 0; count < NUM_CODEC_DAIS; count++) diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index 7b363bdca291..c01150f883ff 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -309,9 +309,9 @@ static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ /* QUAT_TDM_TX */ - {0, 2, 0xFFFF}, - {4, 6, 8, 10, 12, 14, 16, 18}, - {20, 22, 24, 26, 28, 30, 0xFFFF}, + {0, 2, 4, 6, 8, 10, 12, 0xFFFF}, + {14, 16, 0xFFFF}, + {18, 20, 22, 24, 26, 28, 30, 0xFFFF}, {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ @@ -327,9 +327,9 @@ static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {28, 30, 0xFFFF}, {0xFFFF}, /* not used */ /* TERT_TDM_TX */ - {0, 2, 4, 6, 8, 10, 12, 0xFFFF}, - {14, 16, 0xFFFF}, - {18, 20, 22, 24, 26, 28, 30, 0xFFFF}, + {0, 2, 0xFFFF}, + {4, 6, 8, 10, 12, 14, 16, 18}, + {20, 22, 24, 26, 28, 30, 0xFFFF}, {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ @@ -3835,6 +3835,55 @@ static struct snd_soc_dai_link apq8096_custom_fe_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9, .ops = &apq8096_ll_ops, }, + { + .name = "INT_HFP_BT Hostless", + .stream_name = "INT_HFP_BT Hostless", + .cpu_dai_name = "INT_HFP_BT_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Tertiary MI2S TX_Hostless", + .stream_name = "Tertiary MI2S_TX Hostless Capture", + .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, }; static struct snd_soc_dai_link apq8096_common_be_dai_links[] = { diff --git a/sound/usb/Makefile b/sound/usb/Makefile index d2ac0386d3da..083887ba0346 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -13,7 +13,8 @@ snd-usb-audio-objs := card.o \ pcm.o \ proc.o \ quirks.o \ - stream.o + stream.o \ + badd.o snd-usbmidi-lib-objs := midi.o diff --git a/sound/usb/badd.c b/sound/usb/badd.c new file mode 100644 index 000000000000..cc6c26cbb624 --- /dev/null +++ b/sound/usb/badd.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> + +struct uac3_input_terminal_descriptor badd_baif_in_term_desc = { + .bLength = UAC3_DT_INPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_INPUT_TERMINAL, + .bTerminalID = BADD_IN_TERM_ID_BAIF, + .bCSourceID = BADD_CLOCK_SOURCE, + .wExTerminalDescrID = 0x0000, + .wTerminalDescrStr = 0x0000 +}; + +struct uac3_input_terminal_descriptor badd_baof_in_term_desc = { + .bLength = UAC3_DT_INPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_INPUT_TERMINAL, + .bTerminalID = BADD_IN_TERM_ID_BAOF, + .wTerminalType = UAC_TERMINAL_STREAMING, + .bAssocTerminal = 0x00, + .bCSourceID = BADD_CLOCK_SOURCE, + .bmControls = 0x00000000, + .wExTerminalDescrID = 0x0000, + .wConnectorsDescrID = 0x0000, + .wTerminalDescrStr = 0x0000 +}; + +struct uac3_output_terminal_descriptor badd_baif_out_term_desc = { + .bLength = UAC3_DT_OUTPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, + .bTerminalID = BADD_OUT_TERM_ID_BAIF, + .wTerminalType = UAC_TERMINAL_STREAMING, + .bAssocTerminal = 0x00, /* No associated terminal */ + .bSourceID = BADD_FU_ID_BAIF, + .bCSourceID = BADD_CLOCK_SOURCE, + .bmControls = 0x00000000, /* No controls */ + .wExTerminalDescrID = 0x0000, + .wConnectorsDescrID = 0x0000, + .wTerminalDescrStr = 0x0000 +}; + +struct uac3_output_terminal_descriptor badd_baof_out_term_desc = { + .bLength = UAC3_DT_OUTPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, + .bTerminalID = BADD_OUT_TERM_ID_BAOF, + .bSourceID = BADD_FU_ID_BAOF, + .bCSourceID = BADD_CLOCK_SOURCE, + .wExTerminalDescrID = 0x0000, + .wTerminalDescrStr = 0x0000 +}; + +__u8 monoControls[] = { + 0x03, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00}; + +__u8 stereoControls[] = { + 0x03, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00 +}; + +__u8 badd_mu_src_ids[] = {BADD_IN_TERM_ID_BAOF, BADD_FU_ID_BAIOF}; + +struct uac3_mixer_unit_descriptor badd_baiof_mu_desc = { + .bLength = UAC3_DT_MIXER_UNIT_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC3_MIXER_UNIT_V3, + .bUnitID = BADD_MU_ID_BAIOF, + .bNrInPins = 0x02, + .baSourceID = badd_mu_src_ids, + .bmMixerControls = 0x00, + .bmControls = 0x00000000, + .wMixerDescrStr = 0x0000 +}; + +struct uac3_feature_unit_descriptor badd_baif_fu_desc = { + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC3_FEATURE_UNIT_V3, + .bUnitID = BADD_FU_ID_BAIF, + .bSourceID = BADD_IN_TERM_ID_BAIF, + .wFeatureDescrStr = 0x0000 +}; + +struct uac3_feature_unit_descriptor badd_baof_fu_desc = { + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC3_FEATURE_UNIT_V3, + .bUnitID = BADD_FU_ID_BAOF, + .wFeatureDescrStr = 0x0000 +}; + +struct uac3_feature_unit_descriptor badd_baiof_fu_desc = { + .bLength = 0x0f, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC3_FEATURE_UNIT_V3, + .bUnitID = BADD_FU_ID_BAIOF, + .bSourceID = BADD_IN_TERM_ID_BAIF, + .bmaControls = monoControls, + .wFeatureDescrStr = 0x0000 +}; + +struct uac3_clock_source_descriptor badd_clock_desc = { + .bLength = UAC3_DT_CLOCK_SRC_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC3_CLOCK_SOURCE, + .bClockID = BADD_CLOCK_SOURCE, + .bmControls = 0x00000001, + .bReferenceTerminal = 0x00, + .wClockSourceStr = 0x0000 +}; + +void *badd_desc_list[] = { + &badd_baif_in_term_desc, + &badd_baof_in_term_desc, + &badd_baiof_mu_desc, + &badd_baif_fu_desc, + &badd_baof_fu_desc, + &badd_baiof_fu_desc, + &badd_clock_desc +}; + diff --git a/sound/usb/card.c b/sound/usb/card.c index 7bc935bab369..23ea575f3bcf 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -45,6 +45,7 @@ #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> #include <linux/module.h> +#include <linux/usb/audio-v3.h> #include <sound/control.h> #include <sound/core.h> @@ -281,7 +282,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) struct usb_host_interface *host_iface; struct usb_interface_descriptor *altsd; struct usb_interface *usb_iface; - void *control_header; int i, protocol; usb_iface = usb_ifnum_to_if(dev, ctrlif); @@ -298,16 +298,13 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) return -EINVAL; } - control_header = snd_usb_find_csint_desc(host_iface->extra, - host_iface->extralen, - NULL, UAC_HEADER); altsd = get_iface_desc(host_iface); protocol = altsd->bInterfaceProtocol; - if (!control_header) { - dev_err(&dev->dev, "cannot find UAC_HEADER\n"); - return -EINVAL; - } + /* + * UAC 1.0 devices use AC HEADER Desc for linking AS interfaces; + * UAC 2.0 and 3.0 devices use IAD for linking AS interfaces + */ switch (protocol) { default: @@ -317,8 +314,17 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) /* fall through */ case UAC_VERSION_1: { - struct uac1_ac_header_descriptor *h1 = control_header; + void *control_header; + struct uac1_ac_header_descriptor *h1; + + control_header = snd_usb_find_csint_desc(host_iface->extra, + host_iface->extralen, NULL, UAC_HEADER); + if (!control_header) { + dev_err(&dev->dev, "cannot find UAC_HEADER\n"); + return -EINVAL; + } + h1 = control_header; if (!h1->bInCollection) { dev_info(&dev->dev, "skipping empty audio interface (v1)\n"); return -EINVAL; @@ -335,7 +341,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) break; } - case UAC_VERSION_2: { + case UAC_VERSION_2: + case UAC_VERSION_3: { struct usb_interface_assoc_descriptor *assoc = usb_iface->intf_assoc; if (!assoc) { @@ -354,7 +361,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) } if (!assoc) { - dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n"); + dev_err(&dev->dev, "Audio class V%d interfaces need an interface association\n", + protocol); return -EINVAL; } @@ -554,6 +562,15 @@ static int usb_audio_probe(struct usb_interface *intf, struct usb_host_interface *alts; int ifnum; u32 id; + struct usb_interface_assoc_descriptor *assoc; + + assoc = intf->intf_assoc; + if (assoc && assoc->bFunctionClass == USB_CLASS_AUDIO && + assoc->bFunctionProtocol == UAC_VERSION_3 && + assoc->bFunctionSubClass == FULL_ADC_PROFILE) { + dev_info(&dev->dev, "No support for full-fledged ADC 3.0 yet!!\n"); + return -EINVAL; + } alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 7ccbcaf6a147..2cd09ceba5e9 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -424,6 +424,10 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, case UAC_VERSION_2: return set_sample_rate_v2(chip, iface, alts, fmt, rate); + + /* Clock rate is fixed at 48 kHz for BADD devices */ + case UAC_VERSION_3: + return 0; } } diff --git a/sound/usb/format.c b/sound/usb/format.c index 789d19ec035d..2cc3b92f1fba 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -20,6 +20,7 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/pcm.h> @@ -69,6 +70,30 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, format <<= 1; break; } + + case UAC_VERSION_3: { + switch (fp->maxpacksize) { + case BADD_MAXPSIZE_SYNC_MONO_16: + case BADD_MAXPSIZE_SYNC_STEREO_16: + case BADD_MAXPSIZE_ASYNC_MONO_16: + case BADD_MAXPSIZE_ASYNC_STEREO_16: { + sample_width = BIT_RES_16_BIT; + sample_bytes = SUBSLOTSIZE_16_BIT; + break; + } + + case BADD_MAXPSIZE_SYNC_MONO_24: + case BADD_MAXPSIZE_SYNC_STEREO_24: + case BADD_MAXPSIZE_ASYNC_MONO_24: + case BADD_MAXPSIZE_ASYNC_STEREO_24: { + sample_width = BIT_RES_24_BIT; + sample_bytes = SUBSLOTSIZE_24_BIT; + break; + } + } + format = 1 << format; + break; + } } if ((pcm_formats == 0) && @@ -366,6 +391,22 @@ err: return ret; } +static int badd_set_audio_rate_v3(struct snd_usb_audio *chip, + struct audioformat *fp) +{ + unsigned int rate; + + fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL); + if (fp->rate_table == NULL) + return -ENOMEM; + + fp->nr_rates = 1; + rate = BADD_SAMPLING_RATE; + fp->rate_min = fp->rate_max = fp->rate_table[0] = rate; + fp->rates |= snd_pcm_rate_to_rate_bit(rate); + return 0; +} + /* * parse the format type I and III descriptors */ @@ -415,6 +456,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, /* fp->channels is already set in this case */ ret = parse_audio_format_rates_v2(chip, fp); break; + case UAC_VERSION_3: + ret = badd_set_audio_rate_v3(chip, fp); + break; } if (fp->channels < 1) { @@ -502,7 +546,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, fmt->bFormatType); return -ENOTSUPP; } - fp->fmt_type = fmt->bFormatType; + if (fp->protocol == UAC_VERSION_3) + fp->fmt_type = UAC_FORMAT_TYPE_I; + else + fp->fmt_type = fmt->bFormatType; if (err < 0) return err; #if 1 diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 157c0704817c..b9d9d2e99c78 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -50,6 +50,7 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/control.h> @@ -184,6 +185,17 @@ static void *find_audio_control_unit(struct mixer_build *state, /* we just parse the header */ struct uac_feature_unit_descriptor *hdr = NULL; + if (state->mixer->protocol == UAC_VERSION_3) { + int i; + + for (i = 0; i < NUM_BADD_DESCS; i++) { + hdr = (void *)badd_desc_list[i]; + if (hdr->bUnitID == unit) + return hdr; + } + + return NULL; + } while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr, USB_DT_CS_INTERFACE)) != NULL) { if (hdr->bLength >= 4 && @@ -717,7 +729,7 @@ static int check_input_term(struct mixer_build *state, int id, term->channels = d->bNrChannels; term->chconfig = le16_to_cpu(d->wChannelConfig); term->name = d->iTerminal; - } else { /* UAC_VERSION_2 */ + } else if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_input_terminal_descriptor *d = p1; /* call recursively to verify that the @@ -734,6 +746,24 @@ static int check_input_term(struct mixer_build *state, int id, term->channels = d->bNrChannels; term->chconfig = le32_to_cpu(d->bmChannelConfig); term->name = d->iTerminal; + } else { /* UAC_VERSION_3 */ + struct uac3_input_terminal_descriptor *d = p1; + + err = check_input_term(state, + d->bCSourceID, term); + if (err < 0) + return err; + + term->id = id; + term->type = d->wTerminalType; + if (d->wClusterDescrID == CLUSTER_ID_MONO) { + term->channels = NUM_CHANNELS_MONO; + term->chconfig = BADD_CH_CONFIG_MONO; + } else { + term->channels = NUM_CHANNELS_STEREO; + term->chconfig = BADD_CH_CONFIG_STEREO; + } + term->name = d->wTerminalDescrStr; } return 0; case UAC_FEATURE_UNIT: { @@ -751,41 +781,81 @@ static int check_input_term(struct mixer_build *state, int id, return 0; } case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = d->bDescriptorSubtype << 16; /* virtual type */ - term->id = id; - term->name = uac_selector_unit_iSelector(d); + /* UAC3_MIXER_UNIT_V3 */ + case UAC2_CLOCK_SELECTOR: + /* UAC3_CLOCK_SOURCE */ { + if (state->mixer->protocol == UAC_VERSION_3 + && hdr[2] == UAC3_CLOCK_SOURCE) { + struct uac3_clock_source_descriptor *d = p1; + + term->type = d->bDescriptorSubtype << 16; + term->id = id; + term->name = d->wClockSourceStr; + } else if (state->mixer->protocol == UAC_VERSION_3 + && hdr[2] == UAC3_MIXER_UNIT_V3) { + struct uac3_mixer_unit_descriptor *d = p1; + + term->type = d->bDescriptorSubtype << 16; + if (d->wClusterDescrID == CLUSTER_ID_MONO) { + term->channels = NUM_CHANNELS_MONO; + term->chconfig = BADD_CH_CONFIG_MONO; + } else { + term->channels = NUM_CHANNELS_STEREO; + term->chconfig = BADD_CH_CONFIG_STEREO; + } + term->name = d->wMixerDescrStr; + } else { + struct uac_selector_unit_descriptor *d = p1; + /* call recursively to retrieve channel info */ + err = check_input_term(state, + d->baSourceID[0], term); + if (err < 0) + return err; + /* virtual type */ + term->type = d->bDescriptorSubtype << 16; + term->id = id; + term->name = uac_selector_unit_iSelector(d); + } return 0; } case UAC1_PROCESSING_UNIT: case UAC1_EXTENSION_UNIT: /* UAC2_PROCESSING_UNIT_V2 */ /* UAC2_EFFECT_UNIT */ + /* UAC3_FEATURE_UNIT_V3 */ case UAC2_EXTENSION_UNIT_V2: { - struct uac_processing_unit_descriptor *d = p1; + if (state->mixer->protocol == UAC_VERSION_3) { + struct uac_feature_unit_descriptor *d = p1; + + id = d->bSourceID; + } else { + struct uac_processing_unit_descriptor *d = p1; + + if (state->mixer->protocol == UAC_VERSION_2 && + hdr[2] == UAC2_EFFECT_UNIT) { + /* UAC2/UAC1 unit IDs overlap here in an + * uncompatible way. Ignore this unit + * for now. + */ + return 0; + } - if (state->mixer->protocol == UAC_VERSION_2 && - hdr[2] == UAC2_EFFECT_UNIT) { - /* UAC2/UAC1 unit IDs overlap here in an - * uncompatible way. Ignore this unit for now. - */ + if (d->bNrInPins) { + id = d->baSourceID[0]; + break; /* continue to parse */ + } + /* virtual type */ + term->type = d->bDescriptorSubtype << 16; + term->channels = + uac_processing_unit_bNrChannels(d); + term->chconfig = + uac_processing_unit_wChannelConfig( + d, state->mixer->protocol); + term->name = uac_processing_unit_iProcessing( + d, state->mixer->protocol); return 0; } - - if (d->bNrInPins) { - id = d->baSourceID[0]; - break; /* continue to parse */ - } - term->type = d->bDescriptorSubtype << 16; /* virtual type */ - term->channels = uac_processing_unit_bNrChannels(d); - term->chconfig = uac_processing_unit_wChannelConfig(d, state->mixer->protocol); - term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); - return 0; + break; } case UAC2_CLOCK_SOURCE: { struct uac_clock_source_descriptor *d = p1; @@ -1232,12 +1302,18 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, struct usb_feature_control_info *ctl_info; unsigned int len = 0; int mapped_name = 0; - int nameid = uac_feature_unit_iFeature(desc); + int nameid; struct snd_kcontrol *kctl; struct usb_mixer_elem_info *cval; const struct usbmix_name_map *map; unsigned int range; + if (state->mixer->protocol == UAC_VERSION_3) + nameid = ((struct uac3_feature_unit_descriptor *) + raw_desc)->wFeatureDescrStr; + else + nameid = uac_feature_unit_iFeature(desc); + control++; /* change from zero-based to 1-based value */ if (control == UAC_FU_GRAPHIC_EQUALIZER) { @@ -1258,7 +1334,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, ctl_info = &audio_feature_info[control-1]; if (state->mixer->protocol == UAC_VERSION_1) cval->val_type = ctl_info->type; - else /* UAC_VERSION_2 */ + else /* UAC_VERSION_2 or UAC_VERSION_3*/ cval->val_type = ctl_info->type_uac2 >= 0 ? ctl_info->type_uac2 : ctl_info->type; @@ -1381,6 +1457,62 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, snd_usb_mixer_add_control(&cval->head, kctl); } +static int find_num_channels(struct mixer_build *state, int dir) +{ + int num_ch = -EINVAL, num, i, j, wMaxPacketSize; + int ctrlif = get_iface_desc(state->mixer->hostif)->bInterfaceNumber; + struct usb_interface *usb_iface = + usb_ifnum_to_if(state->mixer->chip->dev, ctrlif); + struct usb_interface_assoc_descriptor *assoc = usb_iface->intf_assoc; + struct usb_host_interface *alts; + + for (i = 0; i < assoc->bInterfaceCount; i++) { + int intf = assoc->bFirstInterface + i; + + if (intf != ctrlif) { + struct usb_interface *iface = + usb_ifnum_to_if(state->mixer->chip->dev, intf); + + alts = &iface->altsetting[1]; + if (dir == USB_DIR_OUT && + get_endpoint(alts, 0)->bEndpointAddress & + USB_DIR_IN) + continue; + if (dir == USB_DIR_IN && + !(get_endpoint(alts, 0)->bEndpointAddress & + USB_DIR_IN)) + continue; + num = iface->num_altsetting; + for (j = 1; j < num; j++) { + num_ch = NUM_CHANNELS_MONO; + alts = &iface->altsetting[j]; + wMaxPacketSize = le16_to_cpu( + get_endpoint(alts, 0)-> + wMaxPacketSize); + switch (wMaxPacketSize) { + case BADD_MAXPSIZE_SYNC_MONO_16: + case BADD_MAXPSIZE_SYNC_MONO_24: + case BADD_MAXPSIZE_ASYNC_MONO_16: + case BADD_MAXPSIZE_ASYNC_MONO_24: + break; + case BADD_MAXPSIZE_SYNC_STEREO_16: + case BADD_MAXPSIZE_SYNC_STEREO_24: + case BADD_MAXPSIZE_ASYNC_STEREO_16: + case BADD_MAXPSIZE_ASYNC_STEREO_24: + num_ch = NUM_CHANNELS_STEREO; + break; + } + if (num_ch == NUM_CHANNELS_MONO) + continue; + else + break; + } + } + } + + return num_ch; +} + /* * parse a feature unit * @@ -1412,7 +1544,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unitid); return -EINVAL; } - } else { + } else if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_feature_unit_descriptor *ftr = _ftr; csize = 4; channels = (hdr->bLength - 6) / 4 - 1; @@ -1423,11 +1555,114 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unitid); return -EINVAL; } + } else { + struct usb_interface *usb_iface = + usb_ifnum_to_if(state->mixer->chip->dev, + get_iface_desc(state->mixer->hostif)->bInterfaceNumber); + struct usb_interface_assoc_descriptor *assoc = + usb_iface->intf_assoc; + + csize = 4; + switch (unitid) { + case BADD_FU_ID_BAIOF: + channels = NUM_CHANNELS_MONO; + bmaControls = monoControls; + badd_baif_in_term_desc.wClusterDescrID = + CLUSTER_ID_MONO; + break; + + case BADD_FU_ID_BAOF: + switch (assoc->bFunctionSubClass) { + case PROF_HEADPHONE: + case PROF_HEADSET_ADAPTER: + channels = NUM_CHANNELS_STEREO; + bmaControls = stereoControls; + badd_baiof_mu_desc.wClusterDescrID = + CLUSTER_ID_MONO; + break; + case PROF_SPEAKERPHONE: + channels = NUM_CHANNELS_MONO; + bmaControls = monoControls; + badd_baof_in_term_desc.wClusterDescrID = + CLUSTER_ID_MONO; + break; + default: + channels = find_num_channels(state, + USB_DIR_OUT); + if (channels < 0) { + usb_audio_err(state->chip, + "unit %u: Cant find num of channels\n", + unitid); + return channels; + } + + bmaControls = (channels == NUM_CHANNELS_MONO) ? + monoControls : stereoControls; + badd_baof_in_term_desc.wClusterDescrID = + (channels == NUM_CHANNELS_MONO) ? + CLUSTER_ID_MONO : CLUSTER_ID_STEREO; + break; + } + break; + + case BADD_FU_ID_BAIF: + switch (assoc->bFunctionSubClass) { + case PROF_HEADSET: + case PROF_HEADSET_ADAPTER: + case PROF_SPEAKERPHONE: + channels = NUM_CHANNELS_MONO; + bmaControls = monoControls; + badd_baif_in_term_desc.wClusterDescrID = + CLUSTER_ID_MONO; + break; + default: + channels = find_num_channels(state, USB_DIR_IN); + if (channels < 0) { + usb_audio_err(state->chip, + "unit %u: Cant find num of channels\n", + unitid); + return channels; + } + + bmaControls = (channels == NUM_CHANNELS_MONO) ? + monoControls : stereoControls; + badd_baif_in_term_desc.wClusterDescrID = + (channels == NUM_CHANNELS_MONO) ? + CLUSTER_ID_MONO : CLUSTER_ID_STEREO; + break; + } + break; + } } /* parse the source unit */ - if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0) - return err; + if (state->mixer->protocol != UAC_VERSION_3) { + err = parse_audio_unit(state, hdr->bSourceID); + if (err < 0) + return err; + } else { + struct usb_interface *usb_iface = + usb_ifnum_to_if(state->mixer->chip->dev, + get_iface_desc(state->mixer->hostif)->bInterfaceNumber); + struct usb_interface_assoc_descriptor *assoc = + usb_iface->intf_assoc; + + switch (unitid) { + case BADD_FU_ID_BAOF: + switch (assoc->bFunctionSubClass) { + case PROF_HEADSET: + case PROF_HEADSET_ADAPTER: + hdr->bSourceID = BADD_MU_ID_BAIOF; + break; + default: + hdr->bSourceID = BADD_IN_TERM_ID_BAOF; + break; + } + } + err = parse_audio_unit(state, hdr->bSourceID); + if (err < 0) + return err; + } /* determine the input source type and name */ err = check_input_term(state, hdr->bSourceID, &iterm); @@ -1481,7 +1716,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0); } - } else { /* UAC_VERSION_2 */ + } else { /* UAC_VERSION_2 or UAC_VERSION_3*/ for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) { unsigned int ch_bits = 0; unsigned int ch_read_only = 0; @@ -1599,12 +1834,19 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, int input_pins, num_ins, num_outs; int pin, ich, err; - if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || - !(num_outs = uac_mixer_unit_bNrChannels(desc))) { - usb_audio_err(state->chip, - "invalid MIXER UNIT descriptor %d\n", - unitid); - return -EINVAL; + if (state->mixer->protocol == UAC_VERSION_3) { + input_pins = badd_baiof_mu_desc.bNrInPins; + num_outs = + (badd_baiof_mu_desc.wClusterDescrID == CLUSTER_ID_MONO) ? + NUM_CHANNELS_MONO : NUM_CHANNELS_STEREO; + } else { + if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || + !(num_outs = uac_mixer_unit_bNrChannels(desc))) { + usb_audio_err(state->chip, + "invalid MIXER UNIT descriptor %d\n", + unitid); + return -EINVAL; + } } num_ins = 0; @@ -1624,9 +1866,14 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, int och, ich_has_controls = 0; for (och = 0; och < num_outs; och++) { - __u8 *c = uac_mixer_unit_bmControls(desc, - state->mixer->protocol); + __u8 *c = NULL; + if (state->mixer->protocol == UAC_VERSION_3) + c = + &(badd_baiof_mu_desc.bmMixerControls); + else + c = uac_mixer_unit_bmControls(desc, + state->mixer->protocol); if (check_matrix_bitmap(c, ich, och, num_outs)) { ich_has_controls = 1; break; @@ -2134,16 +2381,28 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) case UAC_MIXER_UNIT: return parse_audio_mixer_unit(state, unitid, p1); case UAC_SELECTOR_UNIT: + /* UAC3_MIXER_UNIT_V3 has the same value */ case UAC2_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); + /* UAC3_CLOCK_SOURCE has the same value */ + if (state->mixer->protocol == UAC_VERSION_3 && + p1[2] == UAC3_CLOCK_SOURCE) + return 0; /* NOP */ + else if (state->mixer->protocol == UAC_VERSION_3 + && p1[2] == UAC3_MIXER_UNIT_V3) + return parse_audio_mixer_unit(state, unitid, p1); + else + return parse_audio_selector_unit(state, unitid, p1); case UAC_FEATURE_UNIT: return parse_audio_feature_unit(state, unitid, p1); case UAC1_PROCESSING_UNIT: /* UAC2_EFFECT_UNIT has the same value */ + /* UAC3_FEATURE_UNIT_V3 has the same value */ if (state->mixer->protocol == UAC_VERSION_1) return parse_audio_processing_unit(state, unitid, p1); - else + else if (state->mixer->protocol == UAC_VERSION_2) return 0; /* FIXME - effect units not implemented yet */ + else + return parse_audio_feature_unit(state, unitid, p1); case UAC1_EXTENSION_UNIT: /* UAC2_PROCESSING_UNIT_V2 has the same value */ if (state->mixer->protocol == UAC_VERSION_1) @@ -2178,6 +2437,23 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) return 0; } +static int make_out_term(struct mixer_build state, int wTerminalType) +{ + struct uac3_output_terminal_descriptor *desc = NULL; + + if (wTerminalType == UAC_TERMINAL_STREAMING) + desc = &badd_baif_out_term_desc; + else { + desc = &badd_baof_out_term_desc; + desc->wTerminalType = wTerminalType; + } + set_bit(desc->bTerminalID, state.unitbitmap); + state.oterm.id = desc->bTerminalID; + state.oterm.type = desc->wTerminalType; + state.oterm.name = desc->wTerminalDescrStr; + return parse_audio_unit(&state, desc->bSourceID); +} + /* * create mixer controls * @@ -2186,9 +2462,8 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) { struct mixer_build state; - int err; + int err = -EINVAL; const struct usbmix_ctl_map *map; - void *p; memset(&state, 0, sizeof(state)); state.chip = mixer->chip; @@ -2206,44 +2481,108 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } } - p = NULL; - while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, - mixer->hostif->extralen, - p, UAC_OUTPUT_TERMINAL)) != NULL) { - if (mixer->protocol == UAC_VERSION_1) { - struct uac1_output_terminal_descriptor *desc = p; - - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ - /* mark terminal ID as visited */ - set_bit(desc->bTerminalID, state.unitbitmap); - state.oterm.id = desc->bTerminalID; - state.oterm.type = le16_to_cpu(desc->wTerminalType); - state.oterm.name = desc->iTerminal; - err = parse_audio_unit(&state, desc->bSourceID); + if (mixer->protocol == UAC_VERSION_3) { + struct usb_interface *usb_iface = + usb_ifnum_to_if(mixer->chip->dev, + get_iface_desc(mixer->hostif)->bInterfaceNumber); + struct usb_interface_assoc_descriptor *assoc = + usb_iface->intf_assoc; + + switch (assoc->bFunctionSubClass) { + case PROF_GENERIC_IO: { + if (assoc->bInterfaceCount == 0x02) { + if (get_endpoint(mixer->hostif, + 0)->bEndpointAddress | USB_DIR_IN) + err = make_out_term(state, + UAC_TERMINAL_STREAMING); + else + err = make_out_term(state, + UAC_OUTPUT_TERMINAL_UNDEFINED); + } else { + err = make_out_term(state, + UAC_OUTPUT_TERMINAL_UNDEFINED); + if (err < 0 && err != -EINVAL) + return err; + err = make_out_term(state, + UAC_TERMINAL_STREAMING); + } + break; + } + + case PROF_HEADPHONE: + err = make_out_term(state, + UAC_OUTPUT_TERMINAL_HEADPHONES); + break; + case PROF_SPEAKER: + err = make_out_term(state, UAC_OUTPUT_TERMINAL_SPEAKER); + break; + case PROF_MICROPHONE: + err = make_out_term(state, UAC_TERMINAL_STREAMING); + break; + case PROF_HEADSET: + case PROF_HEADSET_ADAPTER: + err = make_out_term(state, UAC_BIDIR_TERMINAL_HEADSET); if (err < 0 && err != -EINVAL) return err; - } else { /* UAC_VERSION_2 */ - struct uac2_output_terminal_descriptor *desc = p; - - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ - /* mark terminal ID as visited */ - set_bit(desc->bTerminalID, state.unitbitmap); - state.oterm.id = desc->bTerminalID; - state.oterm.type = le16_to_cpu(desc->wTerminalType); - state.oterm.name = desc->iTerminal; - err = parse_audio_unit(&state, desc->bSourceID); + err = make_out_term(state, UAC_TERMINAL_STREAMING); + break; + case PROF_SPEAKERPHONE: + err = make_out_term(state, + UAC_BIDIR_TERMINAL_SPEAKERPHONE); if (err < 0 && err != -EINVAL) return err; + err = make_out_term(state, UAC_TERMINAL_STREAMING); + break; + } + if (err < 0 && err != -EINVAL) + return err; + } else { + void *p; + + p = NULL; + while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, + mixer->hostif->extralen, p, + UAC_OUTPUT_TERMINAL)) != NULL) { + if (mixer->protocol == UAC_VERSION_1) { + struct uac1_output_terminal_descriptor *desc = + p; + + if (desc->bLength < sizeof(*desc)) + continue; /* invalid descriptor? */ + /* mark terminal ID as visited */ + set_bit(desc->bTerminalID, state.unitbitmap); + state.oterm.id = desc->bTerminalID; + state.oterm.type = + le16_to_cpu(desc->wTerminalType); + state.oterm.name = desc->iTerminal; + err = parse_audio_unit(&state, desc->bSourceID); + if (err < 0 && err != -EINVAL) + return err; + } else { /* UAC_VERSION_2 */ + struct uac2_output_terminal_descriptor *desc = + p; + + if (desc->bLength < sizeof(*desc)) + continue; /* invalid descriptor? */ + /* mark terminal ID as visited */ + set_bit(desc->bTerminalID, state.unitbitmap); + state.oterm.id = desc->bTerminalID; + state.oterm.type = + le16_to_cpu(desc->wTerminalType); + state.oterm.name = desc->iTerminal; + err = parse_audio_unit(&state, desc->bSourceID); + if (err < 0 && err != -EINVAL) + return err; - /* - * For UAC2, use the same approach to also add the - * clock selectors - */ - err = parse_audio_unit(&state, desc->bCSourceID); - if (err < 0 && err != -EINVAL) - return err; + /* + * For UAC2, use the same approach to also add + * the clock selectors + */ + err = parse_audio_unit(&state, + desc->bCSourceID); + if (err < 0 && err != -EINVAL) + return err; + } } } @@ -2478,6 +2817,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, case UAC_VERSION_2: mixer->protocol = UAC_VERSION_2; break; + case UAC_VERSION_3: + mixer->protocol = UAC_VERSION_3; + break; } if ((err = snd_usb_mixer_controls(mixer)) < 0 || diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 98b2c28ae46b..2bb503576134 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -20,6 +20,7 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/pcm.h> @@ -284,8 +285,6 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, 0 /* terminator */ }; struct snd_pcm_chmap_elem *chmap; - const unsigned int *maps; - int c; if (channels > ARRAY_SIZE(chmap->map)) return NULL; @@ -294,27 +293,42 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, if (!chmap) return NULL; - maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps; chmap->channels = channels; - c = 0; - if (bits) { - for (; bits && *maps; maps++, bits >>= 1) - if (bits & 1) - chmap->map[c++] = *maps; + if (protocol == UAC_VERSION_3) { + switch (channels) { + case 1: + chmap->map[0] = SNDRV_CHMAP_MONO; + break; + case 2: + chmap->map[0] = SNDRV_CHMAP_FL; + chmap->map[1] = SNDRV_CHMAP_FR; + break; + } } else { - /* If we're missing wChannelConfig, then guess something - to make sure the channel map is not skipped entirely */ - if (channels == 1) - chmap->map[c++] = SNDRV_CHMAP_MONO; - else - for (; c < channels && *maps; maps++) - chmap->map[c++] = *maps; + int c = 0; + const unsigned int *maps = + protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps; + + if (bits) { + for (; bits && *maps; maps++, bits >>= 1) + if (bits & 1) + chmap->map[c++] = *maps; + } else { + /* + * If we're missing wChannelConfig, then guess something + * to make sure the channel map is not skipped entirely + */ + if (channels == 1) + chmap->map[c++] = SNDRV_CHMAP_MONO; + else + for (; c < channels && *maps; maps++) + chmap->map[c++] = *maps; + } + for (; c < channels; c++) + chmap->map[c] = SNDRV_CHMAP_UNKNOWN; } - for (; c < channels; c++) - chmap->map[c] = SNDRV_CHMAP_UNKNOWN; - return chmap; } @@ -411,6 +425,9 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, struct usb_interface_descriptor *altsd = get_iface_desc(alts); int attributes = 0; + if (protocol == UAC_VERSION_3) + return 0; + csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); /* Creamware Noah has this descriptor after the 2nd endpoint */ @@ -631,6 +648,39 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) iface_no, altno, as->bTerminalLink); continue; } + + case UAC_VERSION_3: { + int wMaxPacketSize; + + format = UAC_FORMAT_TYPE_I_PCM; + clock = BADD_CLOCK_SOURCE; + wMaxPacketSize = le16_to_cpu(get_endpoint(alts, 0) + ->wMaxPacketSize); + switch (wMaxPacketSize) { + case BADD_MAXPSIZE_SYNC_MONO_16: + case BADD_MAXPSIZE_SYNC_MONO_24: + case BADD_MAXPSIZE_ASYNC_MONO_16: + case BADD_MAXPSIZE_ASYNC_MONO_24: { + num_channels = NUM_CHANNELS_MONO; + chconfig = BADD_CH_CONFIG_MONO; + goto populate_fp; + } + + case BADD_MAXPSIZE_SYNC_STEREO_16: + case BADD_MAXPSIZE_SYNC_STEREO_24: + case BADD_MAXPSIZE_ASYNC_STEREO_16: + case BADD_MAXPSIZE_ASYNC_STEREO_24: { + num_channels = NUM_CHANNELS_STEREO; + chconfig = BADD_CH_CONFIG_STEREO; + goto populate_fp; + } + default: + dev_err(&dev->dev, + "%u:%d: invalid wMaxPacketSize\n", + iface_no, altno); + continue; + } + } } /* get format type */ @@ -664,6 +714,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) fp->maxpacksize * 2) continue; +populate_fp: fp = kzalloc(sizeof(*fp), GFP_KERNEL); if (! fp) { dev_err(&dev->dev, "cannot malloc\n"); diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index a495a7f6cb22..14ea2239fe11 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -28,6 +28,7 @@ #include <linux/iommu.h> #include <linux/qcom_iommu.h> #include <linux/platform_device.h> +#include <linux/usb/audio-v3.h> #include "usbaudio.h" #include "card.h" @@ -428,12 +429,14 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, protocol = altsd->bInterfaceProtocol; /* get format type */ - fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, - UAC_FORMAT_TYPE); - if (!fmt) { - pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", __func__, - subs->interface, subs->altset_idx); - goto err; + if (protocol != UAC_VERSION_3) { + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, + UAC_FORMAT_TYPE); + if (!fmt) { + pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", + __func__, subs->interface, subs->altset_idx); + goto err; + } } if (!uadev[card_num].ctrl_intf) { @@ -441,12 +444,15 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, goto err; } - hdr_ptr = snd_usb_find_csint_desc(uadev[card_num].ctrl_intf->extra, - uadev[card_num].ctrl_intf->extralen, - NULL, UAC_HEADER); - if (!hdr_ptr) { - pr_err("%s: no UAC_HEADER desc\n", __func__); - goto err; + if (protocol != UAC_VERSION_3) { + hdr_ptr = snd_usb_find_csint_desc( + uadev[card_num].ctrl_intf->extra, + uadev[card_num].ctrl_intf->extralen, + NULL, UAC_HEADER); + if (!hdr_ptr) { + pr_err("%s: no UAC_HEADER desc\n", __func__); + goto err; + } } if (protocol == UAC_VERSION_1) { @@ -474,6 +480,25 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, resp->usb_audio_spec_revision = ((struct uac2_ac_header_descriptor *)hdr_ptr)->bcdADC; resp->usb_audio_spec_revision_valid = 1; + } else if (protocol == UAC_VERSION_3) { + switch (le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize)) { + case BADD_MAXPSIZE_SYNC_MONO_16: + case BADD_MAXPSIZE_SYNC_STEREO_16: + case BADD_MAXPSIZE_ASYNC_MONO_16: + case BADD_MAXPSIZE_ASYNC_STEREO_16: { + resp->usb_audio_subslot_size = SUBSLOTSIZE_16_BIT; + break; + } + + case BADD_MAXPSIZE_SYNC_MONO_24: + case BADD_MAXPSIZE_SYNC_STEREO_24: + case BADD_MAXPSIZE_ASYNC_MONO_24: + case BADD_MAXPSIZE_ASYNC_STEREO_24: { + resp->usb_audio_subslot_size = SUBSLOTSIZE_24_BIT; + break; + } + } + resp->usb_audio_subslot_size_valid = 1; } else { pr_err("%s: unknown protocol version %x\n", __func__, protocol); goto err; |
