summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidKernel.mk35
-rw-r--r--Documentation/devicetree/bindings/pci/msm_pcie.txt10
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt14
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt8
-rw-r--r--arch/arm/boot/dts/qcom/Makefile20
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi68
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660l.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-cdp.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi11
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-common.dtsi34
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi14
-rw-r--r--arch/arm64/Kconfig7
-rw-r--r--arch/arm64/Makefile4
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig6
-rw-r--r--arch/arm64/configs/msmcortex_defconfig6
-rw-r--r--drivers/android/binder.c6
-rw-r--r--drivers/char/diag/diag_masks.c9
-rw-r--r--drivers/char/diag/diagchar.h1
-rw-r--r--drivers/char/diag/diagfwd.c30
-rw-r--r--drivers/char/diag/diagfwd_glink.c4
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c18
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-8998.c112
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c2
-rw-r--r--drivers/iio/adc/qcom-tadc.c49
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c151
-rw-r--r--drivers/media/platform/msm/vidc/msm_v4l2_vidc.c3
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c32
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c13
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c33
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.h1
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c2
-rw-r--r--drivers/mmc/core/mmc.c2
-rw-r--r--drivers/net/ethernet/msm/msm_rmnet_mhi.c453
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c50
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c43
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c61
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h16
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c15
-rw-r--r--drivers/pci/host/pci-msm.c105
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c11
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_intf.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c11
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_intf.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c29
-rw-r--r--drivers/platform/msm/mhi_uci/mhi_uci.c36
-rw-r--r--drivers/platform/msm/seemp_core/seemp_logk.c11
-rw-r--r--drivers/power/qcom/msm-core.c4
-rw-r--r--drivers/power/supply/qcom/battery.c23
-rw-r--r--drivers/power/supply/qcom/fg-core.h3
-rw-r--r--drivers/power/supply/qcom/fg-reg.h1
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c120
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c2
-rw-r--r--drivers/power/supply/qcom/smb-lib.c13
-rw-r--r--drivers/power/supply/qcom/smb-reg.h10
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c266
-rw-r--r--drivers/pps/clients/pps-gpio.c2
-rw-r--r--drivers/scsi/sd.c8
-rw-r--r--drivers/scsi/sd.h5
-rw-r--r--drivers/scsi/ufs/ufshcd.c20
-rw-r--r--drivers/soc/qcom/glink.c9
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c6
-rw-r--r--drivers/soc/qcom/icnss.c3
-rw-r--r--drivers/soc/qcom/msm_glink_pkt.c3
-rw-r--r--drivers/spi/spi_qsd.c197
-rw-r--r--drivers/spi/spi_qsd.h12
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c2
-rw-r--r--drivers/staging/android/ion/ion_system_secure_heap.c4
-rw-r--r--drivers/usb/gadget/function/f_gsi.c17
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c7
-rw-r--r--include/linux/ieee80211.h3
-rw-r--r--include/linux/msm_mhi.h4
-rw-r--r--include/linux/qpnp/qpnp-revid.h3
-rw-r--r--include/linux/sched.h9
-rw-r--r--include/linux/usb/audio-v3.h172
-rw-r--r--include/net/cfg80211.h12
-rw-r--r--include/uapi/linux/nl80211.h21
-rw-r--r--include/uapi/linux/usb/audio.h1
-rw-r--r--kernel/cpu.c39
-rw-r--r--kernel/sched/core.c21
-rw-r--r--kernel/trace/trace.c2
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/mac80211/mlme.c12
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/mlme.c6
-rw-r--r--net/wireless/nl80211.c39
-rw-r--r--scripts/Makefile.build5
-rw-r--r--scripts/Makefile.dtbo24
-rw-r--r--scripts/Makefile.lib8
-rw-r--r--scripts/dtc/Makefile2
-rw-r--r--security/pfe/pfk_ecryptfs.c2
-rw-r--r--security/pfe/pfk_ecryptfs.h4
-rw-r--r--security/pfe/pfk_ext4.c4
-rw-r--r--security/pfe/pfk_ext4.h4
-rw-r--r--sound/soc/codecs/wcd9335.c2
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c7
-rw-r--r--sound/soc/msm/apq8096-auto.c61
-rw-r--r--sound/usb/Makefile3
-rw-r--r--sound/usb/badd.c137
-rw-r--r--sound/usb/card.c39
-rw-r--r--sound/usb/clock.c4
-rw-r--r--sound/usb/format.c49
-rw-r--r--sound/usb/mixer.c496
-rw-r--r--sound/usb/stream.c87
-rw-r--r--sound/usb/usb_audio_qmi_svc.c49
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,
+ &parallel_psy_desc,
+ &parallel_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, &param);
+ return err;
+
+}
+
+static int switch_to_fair_policy(void)
+{
+ struct sched_param param = { .sched_priority = 0 };
+
+ return sched_setscheduler_nocheck(current, SCHED_NORMAL, &param);
+}
+
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;