summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts1
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts8
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts13
-rw-r--r--arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts10
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi16
-rw-r--r--arch/arm/kernel/stacktrace.c1
-rw-r--r--arch/arm/kvm/init.S5
-rw-r--r--arch/arm/kvm/mmu.c3
-rw-r--r--arch/arm64/configs/sdm660-perf_defconfig1
-rw-r--r--arch/arm64/configs/sdm660_defconfig1
-rw-r--r--arch/arm64/include/asm/asm-uaccess.h13
-rw-r--r--arch/arm64/include/asm/barrier.h18
-rw-r--r--arch/arm64/include/asm/uaccess.h8
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c3
-rw-r--r--arch/arm64/kernel/entry.S6
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c1
-rw-r--r--arch/arm64/kernel/stacktrace.c1
-rw-r--r--arch/powerpc/include/asm/topology.h14
-rw-r--r--arch/powerpc/kernel/eeh_driver.c19
-rw-r--r--arch/powerpc/kernel/setup_64.c4
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c2
-rw-r--r--arch/sparc/Kconfig4
-rw-r--r--arch/sparc/include/asm/mmu_64.h2
-rw-r--r--arch/sparc/include/asm/mmu_context_64.h32
-rw-r--r--arch/sparc/include/asm/pil.h1
-rw-r--r--arch/sparc/include/asm/vio.h1
-rw-r--r--arch/sparc/kernel/irq_64.c17
-rw-r--r--arch/sparc/kernel/kernel.h1
-rw-r--r--arch/sparc/kernel/smp_64.c31
-rw-r--r--arch/sparc/kernel/tsb.S11
-rw-r--r--arch/sparc/kernel/ttable_64.S2
-rw-r--r--arch/sparc/kernel/vio.c68
-rw-r--r--arch/sparc/mm/init_64.c86
-rw-r--r--arch/sparc/mm/tsb.c7
-rw-r--r--arch/sparc/mm/ultra.S5
-rw-r--r--arch/x86/kernel/kvm.c2
-rw-r--r--arch/x86/kvm/cpuid.c20
-rw-r--r--arch/x86/kvm/mmu.c7
-rw-r--r--arch/x86/kvm/mmu.h1
-rw-r--r--arch/x86/kvm/x86.c3
-rw-r--r--crypto/gcm.c6
-rw-r--r--drivers/base/firmware_class.c3
-rw-r--r--drivers/bluetooth/btfm_slim_codec.c31
-rw-r--r--drivers/bluetooth/btfm_slim_wcn3990.c6
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/random.c4
-rw-r--r--drivers/cpufreq/cpufreq.c1
-rw-r--r--drivers/cpuidle/lpm-levels.c6
-rw-r--r--drivers/dma/ep93xx_dma.c2
-rw-r--r--drivers/dma/sh/usb-dmac.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c6
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c283
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h29
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c10
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h3
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h1
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c63
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h12
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c6
-rw-r--r--drivers/gpu/drm/msm/msm_gem_prime.c7
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c156
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.h24
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c9
-rw-r--r--drivers/gpu/drm/msm/sde/sde_formats.c263
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.c171
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h16
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h57
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_mdss.h17
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c7
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c21
-rw-r--r--drivers/iio/light/ltr501.c4
-rw-r--r--drivers/iio/proximity/as3935.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c4
-rw-r--r--drivers/input/mouse/elantech.c16
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c31
-rw-r--r--drivers/media/platform/msm/ais/msm.c88
-rw-r--r--drivers/media/platform/msm/ais/msm.h5
-rw-r--r--drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c143
-rw-r--r--drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h1
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c12
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c8
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c4
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c119
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.h12
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c57
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h7
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_dcvs.c8
-rw-r--r--drivers/misc/cxl/file.c7
-rw-r--r--drivers/misc/qseecom.c4
-rw-r--r--drivers/misc/uid_sys_stats.c10
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c4
-rw-r--r--drivers/net/ethernet/ethoc.c3
-rw-r--r--drivers/net/vxlan.c19
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c120
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h1
-rw-r--r--drivers/net/wireless/cnss/cnss_pci.c62
-rw-r--r--drivers/net/xen-netfront.c4
-rw-r--r--drivers/perf/arm_pmu.c1
-rw-r--r--drivers/platform/msm/gsi/gsi.c29
-rw-r--r--drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_rt.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_client.c17
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c18
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_rt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c3
-rw-r--r--drivers/platform/msm/msm_ext_display.c8
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/power/reset/msm-poweroff.c17
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c1
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c27
-rw-r--r--drivers/power/supply/qcom/smb-lib.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c8
-rw-r--r--drivers/scsi/ufs/ufshcd.c2
-rw-r--r--drivers/soc/qcom/glink.c23
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c2
-rw-r--r--drivers/soc/qcom/icnss.c64
-rw-r--r--drivers/soc/qcom/msm_glink_pkt.c31
-rw-r--r--drivers/soc/qcom/scm.c9
-rw-r--r--drivers/soc/qcom/smp2p_sleepstate.c6
-rw-r--r--drivers/soc/qcom/wcd-dsp-glink.c58
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c9
-rw-r--r--drivers/target/target_core_transport.c23
-rw-r--r--drivers/thermal/qpnp-adc-tm.c61
-rw-r--r--drivers/tty/serial/ifx6x60.c2
-rw-r--r--drivers/tty/serial/sh-sci.c10
-rw-r--r--drivers/tty/tty_io.c3
-rw-r--r--drivers/tty/tty_mutex.c7
-rw-r--r--drivers/usb/chipidea/debug.c3
-rw-r--r--drivers/usb/chipidea/udc.c8
-rw-r--r--drivers/usb/core/config.c8
-rw-r--r--drivers/usb/core/generic.c38
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c13
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_splash_logo.c47
-rw-r--r--drivers/video/fbdev/msm/mdss_smmu.c21
-rw-r--r--drivers/video/fbdev/msm/mdss_smmu.h5
-rw-r--r--drivers/xen/privcmd.c4
-rw-r--r--fs/btrfs/extent-tree.c1
-rw-r--r--fs/btrfs/file.c2
-rw-r--r--fs/btrfs/inode.c4
-rw-r--r--fs/buffer.c12
-rw-r--r--fs/ceph/addr.c2
-rw-r--r--fs/direct-io.c2
-rw-r--r--fs/ext4/extents.c5
-rw-r--r--fs/ext4/file.c50
-rw-r--r--fs/ext4/inode.c9
-rw-r--r--fs/ext4/move_extent.c2
-rw-r--r--fs/jfs/super.c4
-rw-r--r--fs/mbcache.c15
-rw-r--r--fs/mpage.c2
-rw-r--r--fs/nfs/dir.c21
-rw-r--r--fs/nfsd/blocklayout.c4
-rw-r--r--fs/nfsd/nfs4proc.c13
-rw-r--r--fs/nfsd/nfs4xdr.c13
-rw-r--r--fs/nilfs2/btnode.c2
-rw-r--r--fs/nilfs2/inode.c4
-rw-r--r--fs/nilfs2/mdt.c4
-rw-r--r--fs/nilfs2/segment.c2
-rw-r--r--fs/ocfs2/aops.c2
-rw-r--r--fs/ocfs2/file.c2
-rw-r--r--fs/reiserfs/file.c2
-rw-r--r--fs/reiserfs/inode.c2
-rw-r--r--fs/sdcardfs/lookup.c3
-rw-r--r--fs/stat.c3
-rw-r--r--fs/udf/inode.c2
-rw-r--r--fs/ufs/balloc.c26
-rw-r--r--fs/ufs/inode.c9
-rw-r--r--fs/ufs/super.c18
-rw-r--r--fs/ufs/util.h10
-rw-r--r--fs/xfs/xfs_aops.c10
-rw-r--r--fs/xfs/xfs_file.c4
-rw-r--r--fs/xfs/xfs_xattr.c1
-rw-r--r--include/linux/cgroup.h20
-rw-r--r--include/linux/fs.h5
-rw-r--r--include/linux/ipc_router.h1
-rw-r--r--include/linux/memblock.h8
-rw-r--r--include/linux/mmzone.h1
-rw-r--r--include/linux/msm_gsi.h18
-rw-r--r--include/linux/power_supply.h1
-rw-r--r--include/linux/ptrace.h7
-rw-r--r--include/linux/skbuff.h3
-rw-r--r--include/linux/usb.h2
-rw-r--r--include/net/ipv6.h1
-rw-r--r--include/uapi/drm/drm_fourcc.h17
-rw-r--r--include/uapi/drm/msm_drm.h35
-rw-r--r--include/uapi/linux/usb/ch9.h23
-rw-r--r--kernel/cpuset.c4
-rw-r--r--kernel/events/core.c60
-rw-r--r--kernel/events/hw_breakpoint.c2
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/ptrace.c20
-rw-r--r--lib/test_user_copy.c20
-rw-r--r--mm/memblock.c24
-rw-r--r--mm/page_alloc.c25
-rw-r--r--mm/truncate.c2
-rw-r--r--mm/vmstat.c27
-rw-r--r--net/bridge/br_stp_if.c3
-rw-r--r--net/core/dev.c33
-rw-r--r--net/ipc_router/ipc_router_core.c17
-rw-r--r--net/ipv4/af_inet.c2
-rw-r--r--net/ipv4/tcp_cong.c1
-rw-r--r--net/ipv6/ip6_offload.c4
-rw-r--r--net/ipv6/ping.c2
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/ipv6/xfrm6_mode_ro.c2
-rw-r--r--net/ipv6/xfrm6_mode_transport.c2
-rw-r--r--security/keys/key.c5
-rw-r--r--security/keys/keyctl.c4
-rw-r--r--sound/core/timer.c7
-rw-r--r--sound/soc/msm/qdsp6v2/q6adm.c18
-rw-r--r--sound/soc/soc-core.c5
-rw-r--r--sound/usb/mixer.c11
234 files changed, 3010 insertions, 834 deletions
diff --git a/Makefile b/Makefile
index 01d9215a37ec..011b673b7166 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 4
-SUBLEVEL = 71
+SUBLEVEL = 72
EXTRAVERSION =
NAME = Blurry Fish Butt
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts
index fee184663336..9f8d432a3112 100644
--- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts
+++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts
@@ -46,6 +46,14 @@
status = "disabled";
};
};
+
+ qcom,adv7481@70 {
+ status = "disabled";
+ };
+
+ qcom,msm-ba {
+ status = "disabled";
+ };
};
&dsi_adv_7533_2 {
diff --git a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts
index 022841b5e769..bd29c0307576 100644
--- a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts
@@ -90,6 +90,7 @@
&snd_9335 {
qcom,msm-mi2s-master = <1>, <1>, <1>, <0>;
+ qcom,msm-mbhc-hphl-swh = <1>;
};
&wcd_usbc_analog_en1_gpio {
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
index da28e56bc2df..e4e488597efd 100644
--- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
@@ -155,6 +155,7 @@
interrupts = <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 331 IRQ_TYPE_EDGE_RISING>;
+ qcom,deferred-regulator-disable-delay = <80>;
vdd-supply = <&gdsc_gpu_cx>;
clocks = <&clock_gcc clk_gcc_gpu_cfg_ahb_clk>,
<&clock_gcc clk_gcc_bimc_gfx_clk>,
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
index 3c9b8e445ff3..4bcf64185038 100644
--- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
@@ -542,6 +542,7 @@
&mdss_hdmi_cec_active>;
pinctrl-4 = <&mdss_hdmi_hpd_suspend &mdss_hdmi_ddc_suspend
&mdss_hdmi_cec_suspend>;
+ /delete-property/ qcom,pluggable;
};
#include "msm8996-sde-display.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index 7c3f035a841b..80b3437beac6 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -1064,6 +1064,7 @@
qcom,pm-qos-irq-cpu = <0>;
qcom,pm-qos-irq-latency = <70 70>;
+ non-removable;
status = "disabled";
};
@@ -1268,6 +1269,7 @@
qcom,pm-qos-cpu-group-latency-us = <70 70>;
qcom,pm-qos-default-cpu = <0>;
+ non-removable;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
index 1cf61486c9e8..48d5cb78611b 100644
--- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
+++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
@@ -46,6 +46,14 @@
status = "disabled";
};
};
+
+ qcom,adv7481@70 {
+ status = "disabled";
+ };
+
+ qcom,msm-ba {
+ status = "disabled";
+ };
};
&pil_modem {
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts
index 55255261a827..ce1c62d9c2ae 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts
@@ -17,6 +17,7 @@
#include <dt-bindings/clock/msm-clocks-8998.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include "msm8998-mdss-panels.dtsi"
#include "msm8998-qrd.dtsi"
/ {
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index fc546512992d..3f8962de22be 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -3063,8 +3063,8 @@
qcom,msm-core@780000 {
compatible = "qcom,apss-core-ea";
reg = <0x780000 0x1000>;
- qcom,low-hyst-temp = <10>;
- qcom,high-hyst-temp = <5>;
+ qcom,low-hyst-temp = <100>;
+ qcom,high-hyst-temp = <100>;
qcom,polling-interval = <50>;
ea0: ea0 {
diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts
index 227a8999a745..4c4c758daa29 100644
--- a/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts
+++ b/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts
@@ -60,6 +60,19 @@
/delete-node/ &tasha_hph_en0;
/delete-node/ &tasha_hph_en1;
+&qusb_phy0 {
+ qcom,qusb-phy-init-seq = <0xf8 0x80
+ 0xb3 0x84
+ 0x83 0x88
+ 0xc7 0x8c
+ 0x30 0x08
+ 0x79 0x0c
+ 0x21 0x10
+ 0x14 0x9c
+ 0x9f 0x1c
+ 0x00 0x18>;
+};
+
&tasha_snd {
qcom,model = "sdm660-tasha-skus-snd-card";
qcom,audio-routing =
diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts
index 7fb0c9d03825..604823ff416e 100644
--- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts
+++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts
@@ -218,4 +218,14 @@
<0x00188018 0x4>;
reg-names = "qusb_phy_base",
"ref_clk_addr";
+ qcom,qusb-phy-init-seq = <0xf8 0x80
+ 0xb3 0x84
+ 0x83 0x88
+ 0xc7 0x8c
+ 0x30 0x08
+ 0x79 0x0c
+ 0x21 0x10
+ 0x14 0x9c
+ 0x9f 0x1c
+ 0x00 0x18>;
};
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 09528da7ca09..56a6d5105568 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -811,8 +811,8 @@
qcom,msm-core@780000 {
compatible = "qcom,apss-core-ea";
reg = <0x780000 0x1000>;
- qcom,low-hyst-temp = <10>;
- qcom,high-hyst-temp = <5>;
+ qcom,low-hyst-temp = <100>;
+ qcom,high-hyst-temp = <100>;
ea0: ea0 {
sensor = <&sensor_information3>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-pm.dtsi b/arch/arm/boot/dts/qcom/sdm660-pm.dtsi
index 21fab4923331..cdf1e47665fb 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-pm.dtsi
@@ -39,7 +39,7 @@
qcom,vctl-timeout-us = <500>;
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
- qcom,saw2-avs-ctl = <0x1010031>;
+ qcom,saw2-avs-ctl = <0x101c031>;
qcom,saw2-avs-limit = <0x4580458>;
qcom,pfm-port = <0x2>;
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
index 66bea3050586..a4111f6d1b94 100644
--- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
@@ -744,8 +744,8 @@
< (-4000) 4000 7000 19000 (-8000)>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
- <(-32000) (-30000) (-29000) (-23000)
- (-21000)>;
+ <(-32000) (-30000) (-29000) (-38000)
+ (-36000)>;
qcom,cpr-floor-to-ceiling-max-range =
<32000 32000 32000 40000 44000
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index 0a0350cb8c2b..207cc57e8e49 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -865,8 +865,8 @@
qcom,msm-core@780000 {
compatible = "qcom,apss-core-ea";
reg = <0x780000 0x1000>;
- qcom,low-hyst-temp = <10>;
- qcom,high-hyst-temp = <5>;
+ qcom,low-hyst-temp = <100>;
+ qcom,high-hyst-temp = <100>;
ea0: ea0 {
sensor = <&sensor_information1>;
@@ -1232,9 +1232,17 @@
compatible = "qcom,clk-cpu-osm";
reg = <0x179c0000 0x4000>, <0x17916000 0x1000>,
<0x17816000 0x1000>, <0x179d1000 0x1000>,
- <0x00784130 0x8>;
+ <0x00784130 0x8>, <0x17914800 0x800>;
reg-names = "osm", "pwrcl_pll", "perfcl_pll",
- "apcs_common", "perfcl_efuse";
+ "apcs_common", "perfcl_efuse",
+ "pwrcl_acd";
+
+ qcom,acdtd-val = <0x0000a111 0x0000a111>;
+ qcom,acdcr-val = <0x002c5ffd 0x002c5ffd>;
+ qcom,acdsscr-val = <0x00000901 0x00000901>;
+ qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>;
+ qcom,acdextint1-val = <0x2cf9afe 0x2cf9afe>;
+ qcom,acdautoxfer-val = <0x00000015 0x00000015>;
vdd-pwrcl-supply = <&apc0_pwrcl_vreg>;
vdd-perfcl-supply = <&apc1_perfcl_vreg>;
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index 5964c77c593d..a1898c6092d1 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -175,6 +175,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
__save_stack_trace(tsk, trace, 1);
}
+EXPORT_SYMBOL(save_stack_trace_tsk);
void save_stack_trace(struct stack_trace *trace)
{
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
index 3988e72d16ff..bfc5aae0c280 100644
--- a/arch/arm/kvm/init.S
+++ b/arch/arm/kvm/init.S
@@ -110,7 +110,6 @@ __do_hyp_init:
@ - Write permission implies XN: disabled
@ - Instruction cache: enabled
@ - Data/Unified cache: enabled
- @ - Memory alignment checks: enabled
@ - MMU: enabled (this code must be run from an identity mapping)
mrc p15, 4, r0, c1, c0, 0 @ HSCR
ldr r2, =HSCTLR_MASK
@@ -118,8 +117,8 @@ __do_hyp_init:
mrc p15, 0, r1, c1, c0, 0 @ SCTLR
ldr r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C)
and r1, r1, r2
- ARM( ldr r2, =(HSCTLR_M | HSCTLR_A) )
- THUMB( ldr r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) )
+ ARM( ldr r2, =(HSCTLR_M) )
+ THUMB( ldr r2, =(HSCTLR_M | HSCTLR_TE) )
orr r1, r1, r2
orr r0, r0, r1
isb
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 33ee522bb76f..e4a774f7aba1 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -876,6 +876,9 @@ static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
pmd_t *pmd;
pud = stage2_get_pud(kvm, cache, addr);
+ if (!pud)
+ return NULL;
+
if (pud_none(*pud)) {
if (!cache)
return NULL;
diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig
index 6d6fd23095d5..b6cb1a4b8574 100644
--- a/arch/arm64/configs/sdm660-perf_defconfig
+++ b/arch/arm64/configs/sdm660-perf_defconfig
@@ -310,6 +310,7 @@ CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MSM_V2=y
CONFIG_SLIMBUS_MSM_NGD=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index 25566e45c46f..ccef87ff6a04 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -319,6 +319,7 @@ CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MSM_V2=y
CONFIG_SLIMBUS_MSM_NGD=y
diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
new file mode 100644
index 000000000000..be2d2347d995
--- /dev/null
+++ b/arch/arm64/include/asm/asm-uaccess.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_ASM_UACCESS_H
+#define __ASM_ASM_UACCESS_H
+
+/*
+ * Remove the address tag from a virtual address, if present.
+ */
+ .macro clear_address_tag, dst, addr
+ tst \addr, #(1 << 55)
+ bic \dst, \addr, #(0xff << 56)
+ csel \dst, \dst, \addr, eq
+ .endm
+
+#endif
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index c5dbc5cb8f10..0671711b46ab 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -44,23 +44,33 @@
#define smp_store_release(p, v) \
do { \
+ union { typeof(*p) __val; char __c[1]; } __u = \
+ { .__val = (__force typeof(*p)) (v) }; \
compiletime_assert_atomic_type(*p); \
switch (sizeof(*p)) { \
case 1: \
asm volatile ("stlrb %w1, %0" \
- : "=Q" (*p) : "r" (v) : "memory"); \
+ : "=Q" (*p) \
+ : "r" (*(__u8 *)__u.__c) \
+ : "memory"); \
break; \
case 2: \
asm volatile ("stlrh %w1, %0" \
- : "=Q" (*p) : "r" (v) : "memory"); \
+ : "=Q" (*p) \
+ : "r" (*(__u16 *)__u.__c) \
+ : "memory"); \
break; \
case 4: \
asm volatile ("stlr %w1, %0" \
- : "=Q" (*p) : "r" (v) : "memory"); \
+ : "=Q" (*p) \
+ : "r" (*(__u32 *)__u.__c) \
+ : "memory"); \
break; \
case 8: \
asm volatile ("stlr %1, %0" \
- : "=Q" (*p) : "r" (v) : "memory"); \
+ : "=Q" (*p) \
+ : "r" (*(__u64 *)__u.__c) \
+ : "memory"); \
break; \
} \
} while (0)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index ac177d96e773..064cef9ae2d1 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -27,6 +27,7 @@
/*
* User space memory access functions
*/
+#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/thread_info.h>
@@ -119,6 +120,13 @@ static inline void set_fs(mm_segment_t fs)
flag; \
})
+/*
+ * When dealing with data aborts, watchpoints, or instruction traps we may end
+ * up with a tagged userland pointer. Clear the tag to get a sane pointer to
+ * pass on to access_ok(), for instance.
+ */
+#define untagged_addr(addr) sign_extend64(addr, 55)
+
#define access_ok(type, addr, size) __range_ok(addr, size)
#define user_addr_max get_fs
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 884b317e56c3..10d3642deb7c 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -299,7 +299,8 @@ do { \
_ASM_EXTABLE(0b, 4b) \
_ASM_EXTABLE(1b, 4b) \
: "=&r" (res), "+r" (data), "=&r" (temp) \
- : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \
+ : "r" ((unsigned long)addr), "i" (-EAGAIN), \
+ "i" (-EFAULT) \
: "memory"); \
uaccess_disable(); \
} while (0)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 0ea65307f866..7822e36d87fb 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -32,6 +32,7 @@
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/uaccess.h>
+#include <asm/asm-uaccess.h>
#include <asm/unistd.h>
/*
@@ -437,12 +438,13 @@ el1_da:
/*
* Data abort handling
*/
- mrs x0, far_el1
+ mrs x3, far_el1
enable_dbg
// re-enable interrupts if they were enabled in the aborted context
tbnz x23, #7, 1f // PSR_I_BIT
enable_irq
1:
+ clear_address_tag x0, x3
mov x2, sp // struct pt_regs
bl do_mem_abort
@@ -604,7 +606,7 @@ el0_da:
// enable interrupts before calling the main handler
enable_dbg_and_irq
ct_user_exit
- bic x0, x26, #(0xff << 56)
+ clear_address_tag x0, x26
mov x1, x25
mov x2, sp
bl do_mem_abort
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index f4dfd8c41e06..1c694f3c643c 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -36,6 +36,7 @@
#include <asm/traps.h>
#include <asm/cputype.h>
#include <asm/system_misc.h>
+#include <asm/uaccess.h>
/* Breakpoint currently in use for each BRP. */
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index cb3eec8e8e50..1fd1a9a6596f 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -184,6 +184,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
+EXPORT_SYMBOL(save_stack_trace_tsk);
void save_stack_trace(struct stack_trace *trace)
{
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 8b3b46b7b0f2..329771559cbb 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -44,8 +44,22 @@ extern void __init dump_numa_cpu_topology(void);
extern int sysfs_add_device_to_node(struct device *dev, int nid);
extern void sysfs_remove_device_from_node(struct device *dev, int nid);
+static inline int early_cpu_to_node(int cpu)
+{
+ int nid;
+
+ nid = numa_cpu_lookup_table[cpu];
+
+ /*
+ * Fall back to node 0 if nid is unset (it should be, except bugs).
+ * This allows callers to safely do NODE_DATA(early_cpu_to_node(cpu)).
+ */
+ return (nid < 0) ? 0 : nid;
+}
#else
+static inline int early_cpu_to_node(int cpu) { return 0; }
+
static inline void dump_numa_cpu_topology(void) {}
static inline int sysfs_add_device_to_node(struct device *dev, int nid)
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index c314db8b798c..9837c98caabe 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -655,7 +655,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
*/
#define MAX_WAIT_FOR_RECOVERY 300
-static void eeh_handle_normal_event(struct eeh_pe *pe)
+static bool eeh_handle_normal_event(struct eeh_pe *pe)
{
struct pci_bus *frozen_bus;
int rc = 0;
@@ -665,7 +665,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
if (!frozen_bus) {
pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n",
__func__, pe->phb->global_number, pe->addr);
- return;
+ return false;
}
eeh_pe_update_time_stamp(pe);
@@ -790,7 +790,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
pr_info("EEH: Notify device driver to resume\n");
eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
- return;
+ return false;
excess_failures:
/*
@@ -831,7 +831,11 @@ perm_error:
pci_lock_rescan_remove();
pcibios_remove_pci_devices(frozen_bus);
pci_unlock_rescan_remove();
+
+ /* The passed PE should no longer be used */
+ return true;
}
+ return false;
}
static void eeh_handle_special_event(void)
@@ -897,7 +901,14 @@ static void eeh_handle_special_event(void)
*/
if (rc == EEH_NEXT_ERR_FROZEN_PE ||
rc == EEH_NEXT_ERR_FENCED_PHB) {
- eeh_handle_normal_event(pe);
+ /*
+ * eeh_handle_normal_event() can make the PE stale if it
+ * determines that the PE cannot possibly be recovered.
+ * Don't modify the PE state if that's the case.
+ */
+ if (eeh_handle_normal_event(pe))
+ continue;
+
eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
} else {
pci_lock_rescan_remove();
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index a20823210ac0..fe6e800c1357 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -751,7 +751,7 @@ void __init setup_arch(char **cmdline_p)
static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
{
- return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align,
+ return __alloc_bootmem_node(NODE_DATA(early_cpu_to_node(cpu)), size, align,
__pa(MAX_DMA_ADDRESS));
}
@@ -762,7 +762,7 @@ static void __init pcpu_fc_free(void *ptr, size_t size)
static int pcpu_cpu_distance(unsigned int from, unsigned int to)
{
- if (cpu_to_node(from) == cpu_to_node(to))
+ if (early_cpu_to_node(from) == early_cpu_to_node(to))
return LOCAL_DISTANCE;
else
return REMOTE_DISTANCE;
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index e9ff44cd5d86..e8b1027e1b5b 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -110,6 +110,7 @@ static struct property *dlpar_clone_drconf_property(struct device_node *dn)
for (i = 0; i < num_lmbs; i++) {
lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr);
lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index);
+ lmbs[i].aa_index = be32_to_cpu(lmbs[i].aa_index);
lmbs[i].flags = be32_to_cpu(lmbs[i].flags);
}
@@ -553,6 +554,7 @@ static void dlpar_update_drconf_property(struct device_node *dn,
for (i = 0; i < num_lmbs; i++) {
lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr);
lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index);
+ lmbs[i].aa_index = cpu_to_be32(lmbs[i].aa_index);
lmbs[i].flags = cpu_to_be32(lmbs[i].flags);
}
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 3736be630113..894bcaed002e 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -183,9 +183,9 @@ config NR_CPUS
int "Maximum number of CPUs"
depends on SMP
range 2 32 if SPARC32
- range 2 1024 if SPARC64
+ range 2 4096 if SPARC64
default 32 if SPARC32
- default 64 if SPARC64
+ default 4096 if SPARC64
source kernel/Kconfig.hz
diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h
index f7de0dbc38af..83b36a5371ff 100644
--- a/arch/sparc/include/asm/mmu_64.h
+++ b/arch/sparc/include/asm/mmu_64.h
@@ -52,7 +52,7 @@
#define CTX_NR_MASK TAG_CONTEXT_BITS
#define CTX_HW_MASK (CTX_NR_MASK | CTX_PGSZ_MASK)
-#define CTX_FIRST_VERSION ((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL))
+#define CTX_FIRST_VERSION BIT(CTX_VERSION_SHIFT)
#define CTX_VALID(__ctx) \
(!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK))
#define CTX_HWBITS(__ctx) ((__ctx.sparc64_ctx_val) & CTX_HW_MASK)
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h
index b84be675e507..349dd23e2876 100644
--- a/arch/sparc/include/asm/mmu_context_64.h
+++ b/arch/sparc/include/asm/mmu_context_64.h
@@ -17,13 +17,8 @@ extern spinlock_t ctx_alloc_lock;
extern unsigned long tlb_context_cache;
extern unsigned long mmu_context_bmap[];
+DECLARE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm);
void get_new_mmu_context(struct mm_struct *mm);
-#ifdef CONFIG_SMP
-void smp_new_mmu_context_version(void);
-#else
-#define smp_new_mmu_context_version() do { } while (0)
-#endif
-
int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void destroy_context(struct mm_struct *mm);
@@ -74,8 +69,9 @@ void __flush_tlb_mm(unsigned long, unsigned long);
static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk)
{
unsigned long ctx_valid, flags;
- int cpu;
+ int cpu = smp_processor_id();
+ per_cpu(per_cpu_secondary_mm, cpu) = mm;
if (unlikely(mm == &init_mm))
return;
@@ -121,7 +117,6 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
* for the first time, we must flush that context out of the
* local TLB.
*/
- cpu = smp_processor_id();
if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) {
cpumask_set_cpu(cpu, mm_cpumask(mm));
__flush_tlb_mm(CTX_HWBITS(mm->context),
@@ -131,26 +126,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
}
#define deactivate_mm(tsk,mm) do { } while (0)
-
-/* Activate a new MM instance for the current task. */
-static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
- unsigned long flags;
- int cpu;
-
- spin_lock_irqsave(&mm->context.lock, flags);
- if (!CTX_VALID(mm->context))
- get_new_mmu_context(mm);
- cpu = smp_processor_id();
- if (!cpumask_test_cpu(cpu, mm_cpumask(mm)))
- cpumask_set_cpu(cpu, mm_cpumask(mm));
-
- load_secondary_context(mm);
- __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
- tsb_context_switch(mm);
- spin_unlock_irqrestore(&mm->context.lock, flags);
-}
-
+#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, NULL)
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC64_MMU_CONTEXT_H) */
diff --git a/arch/sparc/include/asm/pil.h b/arch/sparc/include/asm/pil.h
index 266937030546..522b43db2ed3 100644
--- a/arch/sparc/include/asm/pil.h
+++ b/arch/sparc/include/asm/pil.h
@@ -20,7 +20,6 @@
#define PIL_SMP_CALL_FUNC 1
#define PIL_SMP_RECEIVE_SIGNAL 2
#define PIL_SMP_CAPTURE 3
-#define PIL_SMP_CTX_NEW_VERSION 4
#define PIL_DEVICE_IRQ 5
#define PIL_SMP_CALL_FUNC_SNGL 6
#define PIL_DEFERRED_PCR_WORK 7
diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h
index 8174f6cdbbbb..9dca7a892978 100644
--- a/arch/sparc/include/asm/vio.h
+++ b/arch/sparc/include/asm/vio.h
@@ -327,6 +327,7 @@ struct vio_dev {
int compat_len;
u64 dev_no;
+ u64 id;
unsigned long channel_id;
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index e22416ce56ea..bfbde8c4ffb2 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -1034,17 +1034,26 @@ static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
{
#ifdef CONFIG_SMP
unsigned long page;
+ void *mondo, *p;
- BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
+ BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > PAGE_SIZE);
+
+ /* Make sure mondo block is 64byte aligned */
+ p = kzalloc(127, GFP_KERNEL);
+ if (!p) {
+ prom_printf("SUN4V: Error, cannot allocate mondo block.\n");
+ prom_halt();
+ }
+ mondo = (void *)(((unsigned long)p + 63) & ~0x3f);
+ tb->cpu_mondo_block_pa = __pa(mondo);
page = get_zeroed_page(GFP_KERNEL);
if (!page) {
- prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
+ prom_printf("SUN4V: Error, cannot allocate cpu list page.\n");
prom_halt();
}
- tb->cpu_mondo_block_pa = __pa(page);
- tb->cpu_list_pa = __pa(page + 64);
+ tb->cpu_list_pa = __pa(page);
#endif
}
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index e7f652be9e61..44f32dd4477f 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -37,7 +37,6 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
/* smp_64.c */
void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs);
void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs);
-void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs);
void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs);
void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs);
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 19cd08d18672..95a9fa0d2195 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -959,37 +959,6 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
preempt_enable();
}
-void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
-{
- struct mm_struct *mm;
- unsigned long flags;
-
- clear_softint(1 << irq);
-
- /* See if we need to allocate a new TLB context because
- * the version of the one we are using is now out of date.
- */
- mm = current->active_mm;
- if (unlikely(!mm || (mm == &init_mm)))
- return;
-
- spin_lock_irqsave(&mm->context.lock, flags);
-
- if (unlikely(!CTX_VALID(mm->context)))
- get_new_mmu_context(mm);
-
- spin_unlock_irqrestore(&mm->context.lock, flags);
-
- load_secondary_context(mm);
- __flush_tlb_mm(CTX_HWBITS(mm->context),
- SECONDARY_CONTEXT);
-}
-
-void smp_new_mmu_context_version(void)
-{
- smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0);
-}
-
#ifdef CONFIG_KGDB
void kgdb_roundup_cpus(unsigned long flags)
{
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index d568c8207af7..395ec1800530 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -470,13 +470,16 @@ __tsb_context_switch:
.type copy_tsb,#function
copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size
* %o2=new_tsb_base, %o3=new_tsb_size
+ * %o4=page_size_shift
*/
sethi %uhi(TSB_PASS_BITS), %g7
srlx %o3, 4, %o3
- add %o0, %o1, %g1 /* end of old tsb */
+ add %o0, %o1, %o1 /* end of old tsb */
sllx %g7, 32, %g7
sub %o3, 1, %o3 /* %o3 == new tsb hash mask */
+ mov %o4, %g1 /* page_size_shift */
+
661: prefetcha [%o0] ASI_N, #one_read
.section .tsb_phys_patch, "ax"
.word 661b
@@ -501,9 +504,9 @@ copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size
/* This can definitely be computed faster... */
srlx %o0, 4, %o5 /* Build index */
and %o5, 511, %o5 /* Mask index */
- sllx %o5, PAGE_SHIFT, %o5 /* Put into vaddr position */
+ sllx %o5, %g1, %o5 /* Put into vaddr position */
or %o4, %o5, %o4 /* Full VADDR. */
- srlx %o4, PAGE_SHIFT, %o4 /* Shift down to create index */
+ srlx %o4, %g1, %o4 /* Shift down to create index */
and %o4, %o3, %o4 /* Mask with new_tsb_nents-1 */
sllx %o4, 4, %o4 /* Shift back up into tsb ent offset */
TSB_STORE(%o2 + %o4, %g2) /* Store TAG */
@@ -511,7 +514,7 @@ copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size
TSB_STORE(%o2 + %o4, %g3) /* Store TTE */
80: add %o0, 16, %o0
- cmp %o0, %g1
+ cmp %o0, %o1
bne,pt %xcc, 90b
nop
diff --git a/arch/sparc/kernel/ttable_64.S b/arch/sparc/kernel/ttable_64.S
index c6dfdaa29e20..170ead662f2a 100644
--- a/arch/sparc/kernel/ttable_64.S
+++ b/arch/sparc/kernel/ttable_64.S
@@ -50,7 +50,7 @@ tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
tl0_irq1: TRAP_IRQ(smp_call_function_client, 1)
tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2)
tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3)
-tl0_irq4: TRAP_IRQ(smp_new_mmu_context_version_client, 4)
+tl0_irq4: BTRAP(0x44)
#else
tl0_irq1: BTRAP(0x41)
tl0_irq2: BTRAP(0x42)
diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c
index cb5789c9f961..34824ca396f0 100644
--- a/arch/sparc/kernel/vio.c
+++ b/arch/sparc/kernel/vio.c
@@ -284,13 +284,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
if (!id) {
dev_set_name(&vdev->dev, "%s", bus_id_name);
vdev->dev_no = ~(u64)0;
+ vdev->id = ~(u64)0;
} else if (!cfg_handle) {
dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id);
vdev->dev_no = *id;
+ vdev->id = ~(u64)0;
} else {
dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name,
*cfg_handle, *id);
vdev->dev_no = *cfg_handle;
+ vdev->id = *id;
}
vdev->dev.parent = parent;
@@ -333,27 +336,84 @@ static void vio_add(struct mdesc_handle *hp, u64 node)
(void) vio_create_one(hp, node, &root_vdev->dev);
}
+struct vio_md_node_query {
+ const char *type;
+ u64 dev_no;
+ u64 id;
+};
+
static int vio_md_node_match(struct device *dev, void *arg)
{
+ struct vio_md_node_query *query = (struct vio_md_node_query *) arg;
struct vio_dev *vdev = to_vio_dev(dev);
- if (vdev->mp == (u64) arg)
- return 1;
+ if (vdev->dev_no != query->dev_no)
+ return 0;
+ if (vdev->id != query->id)
+ return 0;
+ if (strcmp(vdev->type, query->type))
+ return 0;
- return 0;
+ return 1;
}
static void vio_remove(struct mdesc_handle *hp, u64 node)
{
+ const char *type;
+ const u64 *id, *cfg_handle;
+ u64 a;
+ struct vio_md_node_query query;
struct device *dev;
- dev = device_find_child(&root_vdev->dev, (void *) node,
+ type = mdesc_get_property(hp, node, "device-type", NULL);
+ if (!type) {
+ type = mdesc_get_property(hp, node, "name", NULL);
+ if (!type)
+ type = mdesc_node_name(hp, node);
+ }
+
+ query.type = type;
+
+ id = mdesc_get_property(hp, node, "id", NULL);
+ cfg_handle = NULL;
+ mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+ u64 target;
+
+ target = mdesc_arc_target(hp, a);
+ cfg_handle = mdesc_get_property(hp, target,
+ "cfg-handle", NULL);
+ if (cfg_handle)
+ break;
+ }
+
+ if (!id) {
+ query.dev_no = ~(u64)0;
+ query.id = ~(u64)0;
+ } else if (!cfg_handle) {
+ query.dev_no = *id;
+ query.id = ~(u64)0;
+ } else {
+ query.dev_no = *cfg_handle;
+ query.id = *id;
+ }
+
+ dev = device_find_child(&root_vdev->dev, &query,
vio_md_node_match);
if (dev) {
printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
device_unregister(dev);
put_device(dev);
+ } else {
+ if (!id)
+ printk(KERN_ERR "VIO: Removed unknown %s node.\n",
+ type);
+ else if (!cfg_handle)
+ printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n",
+ type, *id);
+ else
+ printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n",
+ type, *cfg_handle, *id);
}
}
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 965655afdbb6..384aba109d7c 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -656,10 +656,58 @@ EXPORT_SYMBOL(__flush_dcache_range);
/* get_new_mmu_context() uses "cache + 1". */
DEFINE_SPINLOCK(ctx_alloc_lock);
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
+unsigned long tlb_context_cache = CTX_FIRST_VERSION;
#define MAX_CTX_NR (1UL << CTX_NR_BITS)
#define CTX_BMAP_SLOTS BITS_TO_LONGS(MAX_CTX_NR)
DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR);
+DEFINE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm) = {0};
+
+static void mmu_context_wrap(void)
+{
+ unsigned long old_ver = tlb_context_cache & CTX_VERSION_MASK;
+ unsigned long new_ver, new_ctx, old_ctx;
+ struct mm_struct *mm;
+ int cpu;
+
+ bitmap_zero(mmu_context_bmap, 1 << CTX_NR_BITS);
+
+ /* Reserve kernel context */
+ set_bit(0, mmu_context_bmap);
+
+ new_ver = (tlb_context_cache & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
+ if (unlikely(new_ver == 0))
+ new_ver = CTX_FIRST_VERSION;
+ tlb_context_cache = new_ver;
+
+ /*
+ * Make sure that any new mm that are added into per_cpu_secondary_mm,
+ * are going to go through get_new_mmu_context() path.
+ */
+ mb();
+
+ /*
+ * Updated versions to current on those CPUs that had valid secondary
+ * contexts
+ */
+ for_each_online_cpu(cpu) {
+ /*
+ * If a new mm is stored after we took this mm from the array,
+ * it will go into get_new_mmu_context() path, because we
+ * already bumped the version in tlb_context_cache.
+ */
+ mm = per_cpu(per_cpu_secondary_mm, cpu);
+
+ if (unlikely(!mm || mm == &init_mm))
+ continue;
+
+ old_ctx = mm->context.sparc64_ctx_val;
+ if (likely((old_ctx & CTX_VERSION_MASK) == old_ver)) {
+ new_ctx = (old_ctx & ~CTX_VERSION_MASK) | new_ver;
+ set_bit(new_ctx & CTX_NR_MASK, mmu_context_bmap);
+ mm->context.sparc64_ctx_val = new_ctx;
+ }
+ }
+}
/* Caller does TLB context flushing on local CPU if necessary.
* The caller also ensures that CTX_VALID(mm->context) is false.
@@ -675,48 +723,30 @@ void get_new_mmu_context(struct mm_struct *mm)
{
unsigned long ctx, new_ctx;
unsigned long orig_pgsz_bits;
- int new_version;
spin_lock(&ctx_alloc_lock);
+retry:
+ /* wrap might have happened, test again if our context became valid */
+ if (unlikely(CTX_VALID(mm->context)))
+ goto out;
orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK);
ctx = (tlb_context_cache + 1) & CTX_NR_MASK;
new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx);
- new_version = 0;
if (new_ctx >= (1 << CTX_NR_BITS)) {
new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
if (new_ctx >= ctx) {
- int i;
- new_ctx = (tlb_context_cache & CTX_VERSION_MASK) +
- CTX_FIRST_VERSION;
- if (new_ctx == 1)
- new_ctx = CTX_FIRST_VERSION;
-
- /* Don't call memset, for 16 entries that's just
- * plain silly...
- */
- mmu_context_bmap[0] = 3;
- mmu_context_bmap[1] = 0;
- mmu_context_bmap[2] = 0;
- mmu_context_bmap[3] = 0;
- for (i = 4; i < CTX_BMAP_SLOTS; i += 4) {
- mmu_context_bmap[i + 0] = 0;
- mmu_context_bmap[i + 1] = 0;
- mmu_context_bmap[i + 2] = 0;
- mmu_context_bmap[i + 3] = 0;
- }
- new_version = 1;
- goto out;
+ mmu_context_wrap();
+ goto retry;
}
}
+ if (mm->context.sparc64_ctx_val)
+ cpumask_clear(mm_cpumask(mm));
mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63));
new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
-out:
tlb_context_cache = new_ctx;
mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits;
+out:
spin_unlock(&ctx_alloc_lock);
-
- if (unlikely(new_version))
- smp_new_mmu_context_version();
}
static int numa_enabled = 1;
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 9cdeca0fa955..266411291634 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -451,7 +451,8 @@ retry_tsb_alloc:
extern void copy_tsb(unsigned long old_tsb_base,
unsigned long old_tsb_size,
unsigned long new_tsb_base,
- unsigned long new_tsb_size);
+ unsigned long new_tsb_size,
+ unsigned long page_size_shift);
unsigned long old_tsb_base = (unsigned long) old_tsb;
unsigned long new_tsb_base = (unsigned long) new_tsb;
@@ -459,7 +460,9 @@ retry_tsb_alloc:
old_tsb_base = __pa(old_tsb_base);
new_tsb_base = __pa(new_tsb_base);
}
- copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size);
+ copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size,
+ tsb_index == MM_TSB_BASE ?
+ PAGE_SHIFT : REAL_HPAGE_SHIFT);
}
mm->context.tsb_block[tsb_index].tsb = new_tsb;
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
index 5d2fd6cd3189..fcf4d27a38fb 100644
--- a/arch/sparc/mm/ultra.S
+++ b/arch/sparc/mm/ultra.S
@@ -971,11 +971,6 @@ xcall_capture:
wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint
retry
- .globl xcall_new_mmu_context_version
-xcall_new_mmu_context_version:
- wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint
- retry
-
#ifdef CONFIG_KGDB
.globl xcall_kgdb_capture
xcall_kgdb_capture:
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 47190bd399e7..cec49ecf5f31 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -161,8 +161,8 @@ void kvm_async_pf_task_wait(u32 token)
*/
rcu_irq_exit();
native_safe_halt();
- rcu_irq_enter();
local_irq_disable();
+ rcu_irq_enter();
}
}
if (!n.halted)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 642e9c93a097..9357b29de9bc 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -737,18 +737,20 @@ out:
static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
{
struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
- int j, nent = vcpu->arch.cpuid_nent;
+ struct kvm_cpuid_entry2 *ej;
+ int j = i;
+ int nent = vcpu->arch.cpuid_nent;
e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT;
/* when no next entry is found, the current entry[i] is reselected */
- for (j = i + 1; ; j = (j + 1) % nent) {
- struct kvm_cpuid_entry2 *ej = &vcpu->arch.cpuid_entries[j];
- if (ej->function == e->function) {
- ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
- return j;
- }
- }
- return 0; /* silence gcc, even though control never reaches here */
+ do {
+ j = (j + 1) % nent;
+ ej = &vcpu->arch.cpuid_entries[j];
+ } while (ej->function != e->function);
+
+ ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
+
+ return j;
}
/* find an entry with matching function, matching index (if needed), and that
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 8eb8a934b531..1049c3c9b877 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3433,12 +3433,15 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
}
-static bool can_do_async_pf(struct kvm_vcpu *vcpu)
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
{
if (unlikely(!lapic_in_kernel(vcpu) ||
kvm_event_needs_reinjection(vcpu)))
return false;
+ if (is_guest_mode(vcpu))
+ return false;
+
return kvm_x86_ops->interrupt_allowed(vcpu);
}
@@ -3454,7 +3457,7 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
if (!async)
return false; /* *pfn has correct page already */
- if (!prefault && can_do_async_pf(vcpu)) {
+ if (!prefault && kvm_can_do_async_pf(vcpu)) {
trace_kvm_try_async_get_page(gva, gfn);
if (kvm_find_async_pf_gfn(vcpu, gfn)) {
trace_kvm_async_pf_doublefault(gva, gfn);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 55ffb7b0f95e..e60fc80f8a9c 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -74,6 +74,7 @@ enum {
int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct);
void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly);
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu);
static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
{
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ae2b9cd358f2..6c82792487e9 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8245,8 +8245,7 @@ bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu)
if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED))
return true;
else
- return !kvm_event_needs_reinjection(vcpu) &&
- kvm_x86_ops->interrupt_allowed(vcpu);
+ return kvm_can_do_async_pf(vcpu);
}
void kvm_arch_start_assignment(struct kvm *kvm)
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 1238b3c5a321..0a12c09d7cb2 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -152,10 +152,8 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
err = crypto_ablkcipher_encrypt(&data->req);
if (err == -EINPROGRESS || err == -EBUSY) {
- err = wait_for_completion_interruptible(
- &data->result.completion);
- if (!err)
- err = data->result.err;
+ wait_for_completion(&data->result.completion);
+ err = data->result.err;
}
if (err)
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 68561696f31b..a1696e1d199f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -311,7 +311,8 @@ static const char * const fw_path[] = {
"/lib/firmware/updates/" UTS_RELEASE,
"/lib/firmware/updates",
"/lib/firmware/" UTS_RELEASE,
- "/lib/firmware"
+ "/lib/firmware",
+ "/lib64/firmware"
};
/*
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 1faebb1759e2..96be0e2f9183 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -26,6 +26,9 @@
#include <sound/tlv.h>
#include <btfm_slim.h>
+static int bt_soc_enable_status;
+
+
static int btfm_slim_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -38,8 +41,31 @@ static unsigned int btfm_slim_codec_read(struct snd_soc_codec *codec,
return 0;
}
+static int bt_soc_status_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = bt_soc_enable_status;
+ return 1;
+}
+
+static int bt_soc_status_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 1;
+}
+
+static const struct snd_kcontrol_new status_controls[] = {
+ SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0,
+ bt_soc_status_get,
+ bt_soc_status_put)
+
+};
+
+
static int btfm_slim_codec_probe(struct snd_soc_codec *codec)
{
+ snd_soc_add_codec_controls(codec, status_controls,
+ ARRAY_SIZE(status_controls));
return 0;
}
@@ -130,6 +156,7 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
struct btfmslim *btfmslim = dai->dev->platform_data;
struct btfmslim_ch *ch;
uint8_t rxport, grp = false, nchan = 1;
+ bt_soc_enable_status = 0;
BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
dai->id, dai->rate);
@@ -171,6 +198,10 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream,
}
ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, grp, nchan);
+
+ /* save the enable channel status */
+ if (ret == 0)
+ bt_soc_enable_status = 1;
return ret;
}
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 77e2973e023c..0c4e0b3d5c2e 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -88,12 +88,12 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
if (rxport) {
- if (enable && btfmslim->sample_rate == 48000) {
- /* For A2DP Rx */
+ if (enable) {
+ /* For SCO Rx, A2DP Rx */
reg_val = 0x1;
port_bit = port_num - 0x10;
reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit);
- BTFMSLIM_DBG("writing reg_val (%d) to reg(%x) for A2DP",
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
reg_val, reg);
ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
if (ret) {
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 0975d23031ea..2898d19fadf5 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -346,7 +346,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma)
phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
/* It's illegal to wrap around the end of the physical address space. */
- if (offset + (phys_addr_t)size < offset)
+ if (offset + (phys_addr_t)size - 1 < offset)
return -EINVAL;
if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
diff --git a/drivers/char/random.c b/drivers/char/random.c
index d93dfebae0bb..1822472dffab 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1798,13 +1798,15 @@ int random_int_secret_init(void)
return 0;
}
+static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash)
+ __aligned(sizeof(unsigned long));
+
/*
* Get a random word for internal kernel use only. Similar to urandom but
* with the goal of minimal entropy pool depletion. As a result, the random
* value is not cryptographically secure but for several uses the cost of
* depleting entropy is too high
*/
-static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
unsigned int get_random_int(void)
{
__u32 *hash;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 93a5273aa459..5f0f983ce173 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2568,6 +2568,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (!(cpufreq_driver->flags & CPUFREQ_STICKY) &&
list_empty(&cpufreq_policy_list)) {
/* if all ->init() calls failed, unregister */
+ ret = -ENODEV;
pr_debug("%s: No CPU initialized for driver %s\n", __func__,
driver_data->name);
goto err_if_unreg;
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index b69e59eeeae1..7cd1bbbe1ee8 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1119,10 +1119,14 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
bool from_idle, int predicted)
{
struct lpm_cluster_level *level = &cluster->levels[idx];
+ struct cpumask online_cpus;
int ret, i;
+ cpumask_and(&online_cpus, &cluster->num_children_in_sync,
+ cpu_online_mask);
+
if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus)
- || is_IPI_pending(&cluster->num_children_in_sync)) {
+ || is_IPI_pending(&online_cpus)) {
return -EPERM;
}
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 57ff46284f15..c97336a2ba92 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -325,6 +325,8 @@ static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
| M2P_CONTROL_ENABLE;
m2p_set_control(edmac, control);
+ edmac->buffer = 0;
+
return 0;
}
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index b1bc945f008f..56410ea75ac5 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -117,7 +117,7 @@ struct usb_dmac {
#define USB_DMASWR 0x0008
#define USB_DMASWR_SWR (1 << 0)
#define USB_DMAOR 0x0060
-#define USB_DMAOR_AE (1 << 2)
+#define USB_DMAOR_AE (1 << 1)
#define USB_DMAOR_DME (1 << 0)
#define USB_DMASAR 0x0000
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
index 57a2e347f04d..0f0094b58d1f 100644
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -893,6 +893,12 @@ static bool ci_dpm_vblank_too_short(struct amdgpu_device *adev)
u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300;
+ /* disable mclk switching if the refresh is >120Hz, even if the
+ * blanking period would allow it
+ */
+ if (amdgpu_dpm_get_vrefresh(adev) > 120)
+ return true;
+
if (vblank_time < switch_limit)
return true;
else
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 64914585c9a5..2ee75a2c1039 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -705,13 +705,22 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm)
u64 clip_pclk;
int rc = 0;
+ mutex_lock(&display->display_lock);
+
if (!hdmi->power_on || !display->connected) {
SDE_ERROR("HDMI display is not ready\n");
+ mutex_unlock(&display->display_lock);
+ return -EINVAL;
+ }
+
+ if (!display->pll_update_enable) {
+ SDE_ERROR("PLL update function is not enabled\n");
+ mutex_unlock(&display->display_lock);
return -EINVAL;
}
/* get current pclk */
- cur_pclk = hdmi->pixclock;
+ cur_pclk = hdmi->actual_pixclock;
/* get desired pclk */
dst_pclk = cur_pclk * (1000000000 + ppm);
do_div(dst_pclk, 1000000000);
@@ -725,13 +734,16 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm)
rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk);
if (rc < 0) {
- SDE_ERROR("PLL update failed, reset clock rate\n");
+ SDE_ERROR("HDMI PLL update failed\n");
+ mutex_unlock(&display->display_lock);
return rc;
}
- hdmi->pixclock = clip_pclk;
+ hdmi->actual_pixclock = clip_pclk;
}
+ mutex_unlock(&display->display_lock);
+
return rc;
}
@@ -767,14 +779,119 @@ static const struct file_operations pll_delta_fops = {
.write = _sde_hdmi_debugfs_pll_delta_write,
};
+/**
+ * _sde_hdmi_enable_pll_update() - Enable the HDMI PLL update function
+ *
+ * @enable: non-zero to enable PLL update function, 0 to disable.
+ * return: 0 on success, non-zero in case of failure.
+ *
+ */
+static int _sde_hdmi_enable_pll_update(struct sde_hdmi *display, s32 enable)
+{
+ struct hdmi *hdmi = display->ctrl.ctrl;
+ int rc = 0;
+
+ mutex_lock(&display->display_lock);
+
+ if (!hdmi->power_on || !display->connected) {
+ SDE_ERROR("HDMI display is not ready\n");
+ mutex_unlock(&display->display_lock);
+ return -EINVAL;
+ }
+
+ if (!enable && hdmi->actual_pixclock != hdmi->pixclock) {
+ /* reset pixel clock when disable */
+ rc = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock);
+ if (rc < 0) {
+ SDE_ERROR("reset clock rate failed\n");
+ mutex_unlock(&display->display_lock);
+ return rc;
+ }
+ }
+ hdmi->actual_pixclock = hdmi->pixclock;
+
+ display->pll_update_enable = !!enable;
+
+ mutex_unlock(&display->display_lock);
+
+ SDE_DEBUG("HDMI PLL update: %s\n",
+ display->pll_update_enable ? "enable" : "disable");
+
+ return rc;
+}
+
+static ssize_t _sde_hdmi_debugfs_pll_enable_read(struct file *file,
+ char __user *buff, size_t count, loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char *buf;
+ u32 len = 0;
+
+ if (!display)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(SZ_1K, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += snprintf(buf, SZ_4K, "%s\n",
+ display->pll_update_enable ? "enable" : "disable");
+
+ if (copy_to_user(buff, buf, len)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ *ppos += len;
+
+ kfree(buf);
+ return len;
+}
+
+static ssize_t _sde_hdmi_debugfs_pll_enable_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[10];
+ int enable = 0;
+
+ if (!display)
+ return -ENODEV;
+
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0; /* end of string */
+
+ if (kstrtoint(buf, 0, &enable))
+ return -EFAULT;
+
+ _sde_hdmi_enable_pll_update(display, enable);
+
+ return count;
+}
+
+static const struct file_operations pll_enable_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_debugfs_pll_enable_read,
+ .write = _sde_hdmi_debugfs_pll_enable_write,
+};
+
static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
{
int rc = 0;
struct dentry *dir, *dump_file, *edid_modes;
struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info;
- struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file;
+ struct dentry *edid_vcdb_info, *edid_vendor_name;
struct dentry *src_hdcp14_support, *src_hdcp22_support;
struct dentry *sink_hdcp22_support, *hdmi_hdcp_state;
+ struct dentry *pll_delta_file, *pll_enable_file;
dir = debugfs_create_dir(display->name, NULL);
if (!dir) {
@@ -796,18 +913,30 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
goto error_remove_dir;
}
- pll_file = debugfs_create_file("pll_delta",
+ pll_delta_file = debugfs_create_file("pll_delta",
0644,
dir,
display,
&pll_delta_fops);
- if (IS_ERR_OR_NULL(pll_file)) {
- rc = PTR_ERR(pll_file);
+ if (IS_ERR_OR_NULL(pll_delta_file)) {
+ rc = PTR_ERR(pll_delta_file);
SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n",
display->name, rc);
goto error_remove_dir;
}
+ pll_enable_file = debugfs_create_file("pll_enable",
+ 0644,
+ dir,
+ display,
+ &pll_enable_fops);
+ if (IS_ERR_OR_NULL(pll_enable_file)) {
+ rc = PTR_ERR(pll_enable_file);
+ SDE_ERROR("[%s]debugfs create pll_enable file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
edid_modes = debugfs_create_file("edid_modes",
0444,
dir,
@@ -1738,6 +1867,106 @@ int sde_hdmi_get_info(struct msm_display_info *info,
return rc;
}
+static void sde_hdmi_panel_set_hdr_infoframe(struct sde_hdmi *display,
+struct drm_msm_ext_panel_hdr_metadata *hdr_meta)
+{
+ u32 packet_payload = 0;
+ u32 packet_header = 0;
+ u32 packet_control = 0;
+ u32 const type_code = 0x87;
+ u32 const version = 0x01;
+ u32 const length = 0x1a;
+ u32 const descriptor_id = 0x00;
+ struct hdmi *hdmi;
+ struct drm_connector *connector;
+
+ if (!display || !hdr_meta) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ hdmi = display->ctrl.ctrl;
+ connector = display->ctrl.ctrl->connector;
+
+ if (!hdmi || !connector) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ if (!connector->hdr_supported) {
+ SDE_ERROR("Sink does not support HDR\n");
+ return;
+ }
+
+ /* Setup Packet header and payload */
+ packet_header = type_code | (version << 8) | (length << 16);
+ hdmi_write(hdmi, HDMI_GENERIC0_HDR, packet_header);
+
+ packet_payload = (hdr_meta->eotf << 8);
+ if (connector->hdr_metadata_type_one) {
+ packet_payload |= (descriptor_id << 16)
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_x[0])
+ << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_0, packet_payload);
+ } else {
+ pr_debug("Metadata Type 1 not supported\n");
+ hdmi_write(hdmi, HDMI_GENERIC0_0, packet_payload);
+ goto enable_packet_control;
+ }
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->display_primaries_x[0]))
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_y[0]) << 8)
+ | (HDMI_GET_MSB(hdr_meta->display_primaries_y[0]) << 16)
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_x[1]) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_1, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->display_primaries_x[1]))
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_y[1]) << 8)
+ | (HDMI_GET_MSB(hdr_meta->display_primaries_y[1]) << 16)
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_x[2]) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_2, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->display_primaries_x[2]))
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_y[2]) << 8)
+ | (HDMI_GET_MSB(hdr_meta->display_primaries_y[2]) << 16)
+ | (HDMI_GET_LSB(hdr_meta->white_point_x) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_3, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->white_point_x))
+ | (HDMI_GET_LSB(hdr_meta->white_point_y) << 8)
+ | (HDMI_GET_MSB(hdr_meta->white_point_y) << 16)
+ | (HDMI_GET_LSB(hdr_meta->max_luminance) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_4, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->max_luminance))
+ | (HDMI_GET_LSB(hdr_meta->min_luminance) << 8)
+ | (HDMI_GET_MSB(hdr_meta->min_luminance) << 16)
+ | (HDMI_GET_LSB(hdr_meta->max_content_light_level) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_5, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->max_content_light_level))
+ | (HDMI_GET_LSB(hdr_meta->max_average_light_level) << 8)
+ | (HDMI_GET_MSB(hdr_meta->max_average_light_level) << 16);
+ hdmi_write(hdmi, HDMI_GENERIC0_6, packet_payload);
+
+enable_packet_control:
+ /*
+ * GENERIC0_LINE | GENERIC0_CONT | GENERIC0_SEND
+ * Setup HDMI TX generic packet control
+ * Enable this packet to transmit every frame
+ * Enable HDMI TX engine to transmit Generic packet 1
+ */
+ packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL);
+ packet_control |= BIT(0) | BIT(1) | BIT(2) | BIT(16);
+ hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control);
+}
+
int sde_hdmi_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
int property_index,
@@ -1749,17 +1978,42 @@ int sde_hdmi_set_property(struct drm_connector *connector,
if (!connector || !display) {
SDE_ERROR("connector=%pK or display=%pK is NULL\n",
connector, display);
- return 0;
+ return -EINVAL;
}
SDE_DEBUG("\n");
- if (property_index == CONNECTOR_PROP_PLL_DELTA)
+ if (property_index == CONNECTOR_PROP_PLL_ENABLE)
+ rc = _sde_hdmi_enable_pll_update(display, value);
+ else if (property_index == CONNECTOR_PROP_PLL_DELTA)
rc = _sde_hdmi_update_pll_delta(display, value);
return rc;
}
+int sde_hdmi_get_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ int property_index,
+ uint64_t *value,
+ void *display)
+{
+ struct sde_hdmi *hdmi_display = display;
+ int rc = 0;
+
+ if (!connector || !hdmi_display) {
+ SDE_ERROR("connector=%pK or display=%pK is NULL\n",
+ connector, hdmi_display);
+ return -EINVAL;
+ }
+
+ mutex_lock(&hdmi_display->display_lock);
+ if (property_index == CONNECTOR_PROP_PLL_ENABLE)
+ *value = hdmi_display->pll_update_enable ? 1 : 0;
+ mutex_unlock(&hdmi_display->display_lock);
+
+ return rc;
+}
+
u32 sde_hdmi_get_num_of_displays(void)
{
u32 count = 0;
@@ -2049,6 +2303,17 @@ sde_hdmi_connector_detect(struct drm_connector *connector,
return status;
}
+int sde_hdmi_pre_kickoff(struct drm_connector *connector,
+ void *display,
+ struct msm_display_kickoff_params *params)
+{
+
+ sde_hdmi_panel_set_hdr_infoframe(display,
+ params->hdr_metadata);
+
+ return 0;
+}
+
int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
{
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 84d8720969be..6b9bcfec031b 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -109,6 +109,7 @@ enum hdmi_tx_feature_type {
* @codec_ready: If audio codec is ready.
* @client_notify_pending: If there is client notification pending.
* @irq_domain: IRQ domain structure.
+ * @pll_update_enable: if it's allowed to update HDMI PLL ppm.
* @notifier: CEC notifider to convey physical address information.
* @root: Debug fs root entry.
*/
@@ -159,6 +160,7 @@ struct sde_hdmi {
struct irq_domain *irq_domain;
struct cec_notifier *notifier;
+ bool pll_update_enable;
struct delayed_work hdcp_cb_work;
struct dss_io_data io[HDMI_TX_MAX_IO];
@@ -345,6 +347,22 @@ int sde_hdmi_set_property(struct drm_connector *connector,
void *display);
/**
+ * sde_hdmi_get_property() - get the connector properties
+ * @connector: Handle to the connector.
+ * @state: Handle to the connector state.
+ * @property_index: property index.
+ * @value: property value.
+ * @display: Handle to the display.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_get_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ int property_index,
+ uint64_t *value,
+ void *display);
+
+/**
* sde_hdmi_bridge_init() - init sde hdmi bridge
* @hdmi: Handle to the hdmi.
*
@@ -434,6 +452,17 @@ bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl);
int sde_hdmi_start_hdcp(struct drm_connector *connector);
void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl);
+
+/*
+ * sde_hdmi_pre_kickoff - program kickoff-time features
+ * @display: Pointer to private display structure
+ * @params: Parameters for kickoff-time programming
+ * Returns: Zero on success
+ */
+int sde_hdmi_pre_kickoff(struct drm_connector *connector,
+ void *display,
+ struct msm_display_kickoff_params *params);
+
#else /*#ifdef CONFIG_DRM_SDE_HDMI*/
static inline u32 sde_hdmi_get_num_of_displays(void)
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index 7af84f5c4229..24d2320683e4 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -494,6 +494,16 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
{
+ struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
+ struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+ mutex_lock(&display->display_lock);
+
+ display->pll_update_enable = false;
+
+ mutex_unlock(&display->display_lock);
}
static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
index 6b310acee0ff..8b69dd31f637 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
@@ -94,6 +94,9 @@
/* default hsyncs for 4k@60 for 200ms */
#define HDMI_DEFAULT_TIMEOUT_HSYNC 28571
+#define HDMI_GET_MSB(x)(x >> 8)
+#define HDMI_GET_LSB(x)(x & 0xff)
+
/*
* Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be
* read by the hardware
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 84b578eaad47..8ca7b36ee0c8 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -56,6 +56,7 @@ struct hdmi {
/* video state: */
bool power_on;
unsigned long int pixclock;
+ unsigned long int actual_pixclock;
void __iomem *mmio;
void __iomem *qfprom_mmio;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index a441f3d15542..367e701b59cb 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -26,11 +26,68 @@
#include "msm_gem.h"
#include "msm_mmu.h"
+static void msm_drm_helper_hotplug_event(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+ char *event_string;
+ char const *connector_name;
+ char *envp[2];
+
+ if (!dev) {
+ DRM_ERROR("hotplug_event failed, invalid input\n");
+ return;
+ }
+
+ if (!dev->mode_config.poll_enabled)
+ return;
+
+ event_string = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!event_string) {
+ DRM_ERROR("failed to allocate event string\n");
+ return;
+ }
+
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_connector(connector, dev) {
+ /* Only handle HPD capable connectors. */
+ if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
+ continue;
+
+ connector->status = connector->funcs->detect(connector, false);
+
+ if (connector->name)
+ connector_name = connector->name;
+ else
+ connector_name = "unknown";
+
+ snprintf(event_string, SZ_4K, "name=%s status=%s\n",
+ connector_name,
+ drm_get_connector_status_name(connector->status));
+ DRM_DEBUG("generating hotplug event [%s]\n", event_string);
+ envp[0] = event_string;
+ envp[1] = NULL;
+ kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
+ envp);
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+ kfree(event_string);
+}
+
static void msm_fb_output_poll_changed(struct drm_device *dev)
{
- struct msm_drm_private *priv = dev->dev_private;
+ struct msm_drm_private *priv = NULL;
+
+ if (!dev) {
+ DRM_ERROR("output_poll_changed failed, invalid input\n");
+ return;
+ }
+
+ priv = dev->dev_private;
+
if (priv->fbdev)
drm_fb_helper_hotplug_event(priv->fbdev);
+ else
+ msm_drm_helper_hotplug_event(dev);
}
static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -602,7 +659,8 @@ static int msm_open(struct drm_device *dev, struct drm_file *file)
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- INIT_LIST_HEAD(&ctx->counters);
+ if (ctx)
+ INIT_LIST_HEAD(&ctx->counters);
msm_submitqueue_init(ctx);
@@ -1839,6 +1897,7 @@ static struct drm_driver msm_driver = {
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
+ .gem_prime_res_obj = msm_gem_prime_res_obj,
.gem_prime_pin = msm_gem_prime_pin,
.gem_prime_unpin = msm_gem_prime_unpin,
.gem_prime_get_sg_table = msm_gem_prime_get_sg_table,
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index c2ccc5d462a7..d696f05e0459 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -143,6 +143,8 @@ enum msm_mdp_crtc_property {
enum msm_mdp_conn_property {
/* blob properties, always put these first */
CONNECTOR_PROP_SDE_INFO,
+ CONNECTOR_PROP_HDR_INFO,
+ CONNECTOR_PROP_HDR_METADATA,
/* # of blob properties */
CONNECTOR_PROP_BLOBCOUNT,
@@ -155,6 +157,7 @@ enum msm_mdp_conn_property {
CONNECTOR_PROP_DST_W,
CONNECTOR_PROP_DST_H,
CONNECTOR_PROP_PLL_DELTA,
+ CONNECTOR_PROP_PLL_ENABLE,
/* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -233,6 +236,14 @@ struct msm_display_info {
};
/**
+ * struct - msm_display_kickoff_params - info for display features at kickoff
+ * @hdr_metadata: HDR metadata info passed from userspace
+ */
+struct msm_display_kickoff_params {
+ struct drm_msm_ext_panel_hdr_metadata *hdr_metadata;
+};
+
+/**
* struct msm_drm_event - defines custom event notification struct
* @base: base object required for event notification by DRM framework.
* @event: event object required for event notification by DRM framework.
@@ -465,6 +476,7 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
void *msm_gem_prime_vmap(struct drm_gem_object *obj);
void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj);
struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct sg_table *sg);
int msm_gem_prime_pin(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 70af0d41f970..d66071672c62 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -1046,7 +1046,7 @@ struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
{
struct drm_gem_object *obj;
struct msm_file_private *ctx = file->driver_priv;
- struct msm_gem_address_space *aspace = ctx->aspace;
+ struct msm_gem_address_space *aspace;
struct msm_gem_object *msm_obj;
struct msm_gem_svm_object *msm_svm_obj;
struct msm_gem_vma *domain = NULL;
@@ -1056,6 +1056,9 @@ struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
int write;
int ret;
+ if (!ctx)
+ return ERR_PTR(-ENODEV);
+
/* if we don't have IOMMU, don't bother pretending we can import: */
if (!iommu_present(&platform_bus_type)) {
dev_err_once(dev->dev, "cannot import without IOMMU\n");
@@ -1078,6 +1081,7 @@ struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
drm_gem_private_object_init(dev, obj, size);
msm_obj = to_msm_bo(obj);
+ aspace = ctx->aspace;
domain = obj_add_domain(&msm_obj->base, aspace);
if (IS_ERR(domain)) {
drm_gem_object_unreference_unlocked(obj);
diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c
index 678018804f3a..9f3c097d011b 100644
--- a/drivers/gpu/drm/msm/msm_gem_prime.c
+++ b/drivers/gpu/drm/msm/msm_gem_prime.c
@@ -80,3 +80,10 @@ void msm_gem_prime_unpin(struct drm_gem_object *obj)
if (!obj->import_attach)
msm_gem_put_pages(obj);
}
+
+struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+ return msm_obj->resv;
+}
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index b9ace0d9e69b..7ccc146f3ae1 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -430,7 +430,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
return -EINVAL;
gpu = priv->gpu;
- if (!gpu)
+ if (!gpu || !ctx)
return -ENXIO;
queue = msm_submitqueue_get(ctx, args->queueid);
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 16049e830b7a..d896e436251f 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -669,6 +669,9 @@ int msm_gpu_counter_put(struct msm_gpu *gpu, struct drm_msm_counter *data,
{
struct msm_context_counter *entry;
+ if (!gpu || !ctx)
+ return -ENODEV;
+
list_for_each_entry(entry, &ctx->counters, node) {
if (entry->groupid == data->groupid &&
entry->counterid == data->counterid) {
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 7538927a4993..0bb8298c1013 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -17,6 +17,12 @@
#include "sde_connector.h"
#include "sde_backlight.h"
+#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
+ (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
+
+#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
+ (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
+
static const struct drm_prop_enum_list e_topology_name[] = {
{SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
{SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
@@ -54,6 +60,36 @@ int sde_connector_get_info(struct drm_connector *connector,
return c_conn->ops.get_info(info, c_conn->display);
}
+int sde_connector_pre_kickoff(struct drm_connector *connector)
+{
+ struct sde_connector *c_conn;
+ struct sde_connector_state *c_state;
+ struct msm_display_kickoff_params params;
+ int rc;
+
+ if (!connector) {
+ SDE_ERROR("invalid argument\n");
+ return -EINVAL;
+ }
+
+ c_conn = to_sde_connector(connector);
+ c_state = to_sde_connector_state(connector->state);
+
+ if (!c_conn->display) {
+ SDE_ERROR("invalid argument\n");
+ return -EINVAL;
+ }
+
+ if (!c_conn->ops.pre_kickoff)
+ return 0;
+
+ params.hdr_metadata = &c_state->hdr_meta;
+
+ rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
+
+ return rc;
+}
+
static void sde_connector_destroy(struct drm_connector *connector)
{
struct sde_connector *c_conn;
@@ -70,7 +106,8 @@ static void sde_connector_destroy(struct drm_connector *connector)
if (c_conn->blob_caps)
drm_property_unreference_blob(c_conn->blob_caps);
-
+ if (c_conn->blob_hdr)
+ drm_property_unreference_blob(c_conn->blob_hdr);
msm_property_destroy(&c_conn->property_info);
drm_connector_unregister(connector);
@@ -204,6 +241,68 @@ sde_connector_atomic_duplicate_state(struct drm_connector *connector)
return &c_state->base;
}
+static int _sde_connector_set_hdr_info(
+ struct sde_connector *c_conn,
+ struct sde_connector_state *c_state,
+ void *usr_ptr)
+{
+ struct drm_connector *connector;
+ struct drm_msm_ext_panel_hdr_metadata *hdr_meta;
+ int i;
+
+ if (!c_conn || !c_state) {
+ SDE_ERROR_CONN(c_conn, "invalid args\n");
+ return -EINVAL;
+ }
+
+ connector = &c_conn->base;
+
+ if (!connector->hdr_supported) {
+ SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n");
+ return -ENOTSUPP;
+ }
+
+ memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
+
+ if (!usr_ptr) {
+ SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n");
+ return 0;
+ }
+
+ if (copy_from_user(&c_state->hdr_meta,
+ (void __user *)usr_ptr,
+ sizeof(*hdr_meta))) {
+ SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n");
+ return -EFAULT;
+ }
+
+ hdr_meta = &c_state->hdr_meta;
+
+ SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n",
+ hdr_meta->hdr_supported);
+ SDE_DEBUG_CONN(c_conn, "eotf %d\n",
+ hdr_meta->eotf);
+ SDE_DEBUG_CONN(c_conn, "white_point_x %d\n",
+ hdr_meta->white_point_x);
+ SDE_DEBUG_CONN(c_conn, "white_point_y %d\n",
+ hdr_meta->white_point_y);
+ SDE_DEBUG_CONN(c_conn, "max_luminance %d\n",
+ hdr_meta->max_luminance);
+ SDE_DEBUG_CONN(c_conn, "max_content_light_level %d\n",
+ hdr_meta->max_content_light_level);
+ SDE_DEBUG_CONN(c_conn, "max_average_light_level %d\n",
+ hdr_meta->max_average_light_level);
+
+ for (i = 0; i < HDR_PRIMARIES_COUNT; i++) {
+ SDE_DEBUG_CONN(c_conn, "display_primaries_x [%d]\n",
+ hdr_meta->display_primaries_x[i]);
+ SDE_DEBUG_CONN(c_conn, "display_primaries_y [%d]\n",
+ hdr_meta->display_primaries_y[i]);
+ }
+
+ return 0;
+}
+
static int sde_connector_atomic_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
struct drm_property *property,
@@ -263,6 +362,12 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
SDE_ERROR("invalid topology_control: 0x%llX\n", val);
}
+ if (idx == CONNECTOR_PROP_HDR_METADATA) {
+ rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val);
+ if (rc)
+ SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc);
+ }
+
/* check for custom property handling */
if (!rc && c_conn->ops.set_property) {
rc = c_conn->ops.set_property(connector,
@@ -355,6 +460,32 @@ void sde_connector_complete_commit(struct drm_connector *connector)
sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
}
+static void sde_connector_update_hdr_props(struct drm_connector *connector)
+{
+ struct sde_connector *c_conn = to_sde_connector(connector);
+ struct drm_msm_ext_panel_hdr_properties hdr_prop = {};
+
+ hdr_prop.hdr_supported = connector->hdr_supported;
+
+ if (hdr_prop.hdr_supported) {
+ hdr_prop.hdr_eotf =
+ connector->hdr_eotf;
+ hdr_prop.hdr_metadata_type_one =
+ connector->hdr_metadata_type_one;
+ hdr_prop.hdr_max_luminance =
+ connector->hdr_max_luminance;
+ hdr_prop.hdr_avg_luminance =
+ connector->hdr_avg_luminance;
+ hdr_prop.hdr_min_luminance =
+ connector->hdr_min_luminance;
+ }
+ msm_property_set_blob(&c_conn->property_info,
+ &c_conn->blob_hdr,
+ &hdr_prop,
+ sizeof(hdr_prop),
+ CONNECTOR_PROP_HDR_INFO);
+}
+
static enum drm_connector_status
sde_connector_detect(struct drm_connector *connector, bool force)
{
@@ -392,6 +523,7 @@ static const struct drm_connector_funcs sde_connector_ops = {
static int sde_connector_get_modes(struct drm_connector *connector)
{
struct sde_connector *c_conn;
+ int ret = 0;
if (!connector) {
SDE_ERROR("invalid connector\n");
@@ -403,8 +535,11 @@ static int sde_connector_get_modes(struct drm_connector *connector)
SDE_DEBUG("missing get_modes callback\n");
return 0;
}
+ ret = c_conn->ops.get_modes(connector, c_conn->display);
+ if (ret)
+ sde_connector_update_hdr_props(connector);
- return c_conn->ops.get_modes(connector, c_conn->display);
+ return ret;
}
static enum drm_mode_status
@@ -575,6 +710,17 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
kfree(info);
}
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
+ msm_property_install_blob(&c_conn->property_info,
+ "hdr_properties",
+ DRM_MODE_PROP_IMMUTABLE,
+ CONNECTOR_PROP_HDR_INFO);
+ }
+
+ msm_property_install_volatile_range(&c_conn->property_info,
+ "hdr_metadata", 0x0, 0, ~0, 0,
+ CONNECTOR_PROP_HDR_METADATA);
+
msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
@@ -582,6 +728,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
"PLL_DELTA", 0x0, INT_MIN, INT_MAX, 0,
CONNECTOR_PROP_PLL_DELTA);
+ msm_property_install_volatile_range(&c_conn->property_info,
+ "PLL_ENABLE", 0x0, 0, 1, 0,
+ CONNECTOR_PROP_PLL_ENABLE);
+
/* enum/bitmask properties */
msm_property_install_enum(&c_conn->property_info, "topology_name",
DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
@@ -608,6 +758,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
error_destroy_property:
if (c_conn->blob_caps)
drm_property_unreference_blob(c_conn->blob_caps);
+ if (c_conn->blob_hdr)
+ drm_property_unreference_blob(c_conn->blob_hdr);
msm_property_destroy(&c_conn->property_info);
error_unregister_conn:
drm_connector_unregister(&c_conn->base);
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 3f26ee7d5965..19e2b8a3e41c 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -122,6 +122,19 @@ struct sde_connector_ops {
int (*get_info)(struct msm_display_info *info, void *display);
int (*set_backlight)(void *display, u32 bl_lvl);
+
+
+ /**
+ * pre_kickoff - trigger display to program kickoff-time features
+ * @connector: Pointer to drm connector structure
+ * @display: Pointer to private display structure
+ * @params: Parameter bundle of connector-stored information for
+ * kickoff-time programming into the display
+ * Returns: Zero on success
+ */
+ int (*pre_kickoff)(struct drm_connector *connector,
+ void *display,
+ struct msm_display_kickoff_params *params);
};
/**
@@ -139,6 +152,7 @@ struct sde_connector_ops {
* @property_info: Private structure for generic property handling
* @property_data: Array of private data for generic property handling
* @blob_caps: Pointer to blob structure for 'capabilities' property
+ * @blob_hdr: Pointer to blob structure for 'hdr_properties' property
*/
struct sde_connector {
struct drm_connector base;
@@ -159,6 +173,7 @@ struct sde_connector {
struct msm_property_info property_info;
struct msm_property_data property_data[CONNECTOR_PROP_COUNT];
struct drm_property_blob *blob_caps;
+ struct drm_property_blob *blob_hdr;
};
/**
@@ -206,12 +221,14 @@ struct sde_connector {
* @out_fb: Pointer to output frame buffer, if applicable
* @aspace: Address space for accessing frame buffer objects, if applicable
* @property_values: Local cache of current connector property values
+ * @hdr_meta: HDR metadata info passed from userspace
*/
struct sde_connector_state {
struct drm_connector_state base;
struct drm_framebuffer *out_fb;
struct msm_gem_address_space *aspace;
uint64_t property_values[CONNECTOR_PROP_COUNT];
+ struct drm_msm_ext_panel_hdr_metadata hdr_meta;
};
/**
@@ -303,5 +320,12 @@ void sde_connector_complete_commit(struct drm_connector *connector);
int sde_connector_get_info(struct drm_connector *connector,
struct msm_display_info *info);
+/**
+ * sde_connector_pre_kickoff - trigger kickoff time feature programming
+ * @connector: Pointer to drm connector object
+ * Returns: Zero on success
+ */
+int sde_connector_pre_kickoff(struct drm_connector *connector);
+
#endif /* _SDE_CONNECTOR_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 030b192e5df4..fa03fc8f7ac9 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -795,6 +795,7 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
unsigned int i;
+ int rc;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
@@ -811,6 +812,14 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
if (phys && phys->ops.prepare_for_kickoff)
phys->ops.prepare_for_kickoff(phys);
}
+
+ if (sde_enc->cur_master && sde_enc->cur_master->connector) {
+ rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
+ if (rc)
+ SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n",
+ sde_enc->cur_master->connector->base.id,
+ rc);
+ }
}
void sde_encoder_kickoff(struct drm_encoder *drm_enc)
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index a59ec31ba276..49b3d8e96938 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -11,12 +11,15 @@
*/
#include <uapi/drm/drm_fourcc.h>
+#include <uapi/media/msm_media_info.h>
#include "sde_kms.h"
#include "sde_formats.h"
#define SDE_UBWC_META_MACRO_W_H 16
#define SDE_UBWC_META_BLOCK_SIZE 256
+#define SDE_UBWC_PLANE_SIZE_ALIGNMENT 4096
+
#define SDE_MAX_IMG_WIDTH 0x3FFF
#define SDE_MAX_IMG_HEIGHT 0x3FFF
@@ -42,7 +45,7 @@ bp, flg, fm, np) \
.unpack_count = uc, \
.bpp = bp, \
.fetch_mode = fm, \
- .flag = flg, \
+ .flag = {(flg)}, \
.num_planes = np \
}
@@ -60,7 +63,7 @@ alpha, chroma, count, bp, flg, fm, np) \
.unpack_count = count, \
.bpp = bp, \
.fetch_mode = fm, \
- .flag = flg, \
+ .flag = {(flg)}, \
.num_planes = np \
}
@@ -77,7 +80,24 @@ alpha, chroma, count, bp, flg, fm, np) \
.unpack_count = 2, \
.bpp = 2, \
.fetch_mode = fm, \
- .flag = flg, \
+ .flag = {(flg)}, \
+ .num_planes = np \
+}
+
+#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \
+ .alpha_enable = false, \
+ .element = { (e0), (e1), 0, 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 1, \
+ .unpack_tight = 0, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
.num_planes = np \
}
@@ -95,10 +115,20 @@ flg, fm, np) \
.unpack_count = 1, \
.bpp = bp, \
.fetch_mode = fm, \
- .flag = flg, \
+ .flag = {(flg)}, \
.num_planes = np \
}
+/*
+ * struct sde_media_color_map - maps drm format to media format
+ * @format: DRM base pixel format
+ * @color: Media API color related to DRM format
+ */
+struct sde_media_color_map {
+ uint32_t format;
+ uint32_t color;
+};
+
static const struct sde_format sde_format_map[] = {
INTERLEAVED_RGB_FMT(ARGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
@@ -270,49 +300,49 @@ static const struct sde_format sde_format_map[] = {
INTERLEAVED_RGB_FMT(BGRA1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ARGB2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
@@ -384,31 +414,31 @@ static const struct sde_format sde_format_map[] = {
* the data will be passed by user-space.
*/
static const struct sde_format sde_format_map_ubwc[] = {
- INTERLEAVED_RGB_FMT(RGB565,
+ INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, 0,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBA8888,
+ INTERLEAVED_RGB_FMT(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBX8888,
+ INTERLEAVED_RGB_FMT(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, 0,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBA1010102,
+ INTERLEAVED_RGB_FMT(ABGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBX1010102,
+ INTERLEAVED_RGB_FMT(XBGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX,
@@ -421,6 +451,30 @@ static const struct sde_format sde_format_map_ubwc[] = {
SDE_FETCH_UBWC, 4),
};
+static const struct sde_format sde_format_map_p010[] = {
+ PSEUDO_YUV_FMT_LOOSE(NV12,
+ 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C1_B_Cb, C2_R_Cr,
+ SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
+ SDE_FETCH_LINEAR, 2),
+};
+
+static const struct sde_format sde_format_map_p010_ubwc[] = {
+ PSEUDO_YUV_FMT_LOOSE(NV12,
+ 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C1_B_Cb, C2_R_Cr,
+ SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
+ SDE_FETCH_UBWC, 4),
+};
+
+static const struct sde_format sde_format_map_tp10_ubwc[] = {
+ PSEUDO_YUV_FMT(NV12,
+ 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C1_B_Cb, C2_R_Cr,
+ SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
+ SDE_FETCH_UBWC, 4),
+};
+
/* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support
* Note: Not using the drm_format_*_subsampling since we have formats
*/
@@ -452,6 +506,37 @@ static void _sde_get_v_h_subsample_rate(
}
}
+static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt)
+{
+ static const struct sde_media_color_map sde_media_ubwc_map[] = {
+ {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC},
+ {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC},
+ {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+ {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+ {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC},
+ };
+ int color_fmt = -1;
+ int i;
+
+ if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
+ if (SDE_FORMAT_IS_DX(fmt)) {
+ if (fmt->unpack_tight)
+ color_fmt = COLOR_FMT_NV12_BPP10_UBWC;
+ else
+ color_fmt = COLOR_FMT_P010_UBWC;
+ } else
+ color_fmt = COLOR_FMT_NV12_UBWC;
+ return color_fmt;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sde_media_ubwc_map); ++i)
+ if (fmt->base.pixel_format == sde_media_ubwc_map[i].format) {
+ color_fmt = sde_media_ubwc_map[i].color;
+ break;
+ }
+ return color_fmt;
+}
+
static int _sde_format_get_plane_sizes_ubwc(
const struct sde_format *fmt,
const uint32_t width,
@@ -459,6 +544,7 @@ static int _sde_format_get_plane_sizes_ubwc(
struct sde_hw_fmt_layout *layout)
{
int i;
+ int color;
memset(layout, 0, sizeof(struct sde_hw_fmt_layout));
layout->format = fmt;
@@ -466,84 +552,53 @@ static int _sde_format_get_plane_sizes_ubwc(
layout->height = height;
layout->num_planes = fmt->num_planes;
- if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
- uint32_t y_stride_alignment, uv_stride_alignment;
- uint32_t y_height_alignment, uv_height_alignment;
- uint32_t y_tile_width = 32;
- uint32_t y_tile_height = 8;
- uint32_t uv_tile_width = y_tile_width / 2;
- uint32_t uv_tile_height = y_tile_height;
- uint32_t y_bpp_numer = 1, y_bpp_denom = 1;
- uint32_t uv_bpp_numer = 1, uv_bpp_denom = 1;
-
- y_stride_alignment = 128;
- uv_stride_alignment = 64;
- y_height_alignment = 32;
- uv_height_alignment = 32;
- y_bpp_numer = 1;
- uv_bpp_numer = 2;
- y_bpp_denom = 1;
- uv_bpp_denom = 1;
+ color = _sde_format_get_media_color_ubwc(fmt);
+ if (color < 0) {
+ DRM_ERROR("UBWC format not supported for fmt:0x%X\n",
+ fmt->base.pixel_format);
+ return -EINVAL;
+ }
+
+ if (SDE_FORMAT_IS_YUV(layout->format)) {
+ uint32_t y_sclines, uv_sclines;
+ uint32_t y_meta_scanlines = 0;
+ uint32_t uv_meta_scanlines = 0;
layout->num_planes = 4;
- /* Y bitstream stride and plane size */
- layout->plane_pitch[0] = ALIGN(width, y_stride_alignment);
- layout->plane_pitch[0] = (layout->plane_pitch[0] * y_bpp_numer)
- / y_bpp_denom;
- layout->plane_size[0] = ALIGN(layout->plane_pitch[0] *
- ALIGN(height, y_height_alignment), 4096);
-
- /* CbCr bitstream stride and plane size */
- layout->plane_pitch[1] = ALIGN(width / 2, uv_stride_alignment);
- layout->plane_pitch[1] = (layout->plane_pitch[1] * uv_bpp_numer)
- / uv_bpp_denom;
- layout->plane_size[1] = ALIGN(layout->plane_pitch[1] *
- ALIGN(height / 2, uv_height_alignment), 4096);
-
- /* Y meta data stride and plane size */
- layout->plane_pitch[2] = ALIGN(
- DIV_ROUND_UP(width, y_tile_width), 64);
- layout->plane_size[2] = ALIGN(layout->plane_pitch[2] *
- ALIGN(DIV_ROUND_UP(height, y_tile_height), 16), 4096);
-
- /* CbCr meta data stride and plane size */
- layout->plane_pitch[3] = ALIGN(
- DIV_ROUND_UP(width / 2, uv_tile_width), 64);
- layout->plane_size[3] = ALIGN(layout->plane_pitch[3] *
- ALIGN(DIV_ROUND_UP(height / 2, uv_tile_height), 16),
- 4096);
-
- } else if (fmt->base.pixel_format == DRM_FORMAT_ABGR8888 ||
- fmt->base.pixel_format == DRM_FORMAT_XBGR8888 ||
- fmt->base.pixel_format == DRM_FORMAT_BGRA1010102 ||
- fmt->base.pixel_format == DRM_FORMAT_BGRX1010102 ||
- fmt->base.pixel_format == DRM_FORMAT_BGR565) {
-
- uint32_t stride_alignment, aligned_bitstream_width;
-
- if (fmt->base.pixel_format == DRM_FORMAT_BGR565)
- stride_alignment = 128;
- else
- stride_alignment = 64;
- layout->num_planes = 3;
+ layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width);
+ y_sclines = VENUS_Y_SCANLINES(color, height);
+ layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
+ y_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+ layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width);
+ uv_sclines = VENUS_UV_SCANLINES(color, height);
+ layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] *
+ uv_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+ layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width);
+ y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height);
+ layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
+ y_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+ layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width);
+ uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height);
+ layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] *
+ uv_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
- /* Nothing in plane[1] */
+ } else {
+ uint32_t rgb_scanlines, rgb_meta_scanlines;
- /* RGB bitstream stride and plane size */
- aligned_bitstream_width = ALIGN(width, stride_alignment);
- layout->plane_pitch[0] = aligned_bitstream_width * fmt->bpp;
- layout->plane_size[0] = ALIGN(fmt->bpp * aligned_bitstream_width
- * ALIGN(height, 16), 4096);
+ layout->num_planes = 3;
- /* RGB meta data stride and plane size */
- layout->plane_pitch[2] = ALIGN(DIV_ROUND_UP(
- aligned_bitstream_width, 16), 64);
- layout->plane_size[2] = ALIGN(layout->plane_pitch[2] *
- ALIGN(DIV_ROUND_UP(height, 4), 16), 4096);
- } else {
- DRM_ERROR("UBWC format not supported for fmt:0x%X\n",
- fmt->base.pixel_format);
- return -EINVAL;
+ layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width);
+ rgb_scanlines = VENUS_RGB_SCANLINES(color, height);
+ layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] *
+ rgb_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
+
+ layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width);
+ rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height);
+ layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] *
+ rgb_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT);
}
for (i = 0; i < SDE_MAX_PLANES; i++)
@@ -574,6 +629,7 @@ static int _sde_format_get_plane_sizes_linear(
} else {
uint32_t v_subsample, h_subsample;
uint32_t chroma_samp;
+ uint32_t bpp = 1;
chroma_samp = fmt->chroma_sample;
_sde_get_v_h_subsample_rate(chroma_samp, &v_subsample,
@@ -584,8 +640,11 @@ static int _sde_format_get_plane_sizes_linear(
return -EINVAL;
}
- layout->plane_pitch[0] = width;
- layout->plane_pitch[1] = width / h_subsample;
+ if ((fmt->base.pixel_format == DRM_FORMAT_NV12) &&
+ (SDE_FORMAT_IS_DX(fmt)))
+ bpp = 2;
+ layout->plane_pitch[0] = width * bpp;
+ layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample;
layout->plane_size[0] = layout->plane_pitch[0] * height;
layout->plane_size[1] = layout->plane_pitch[1] *
(height / v_subsample);
@@ -874,7 +933,8 @@ int sde_format_check_modified_format(
DRM_ERROR("invalid handle for plane %d\n", i);
return -EINVAL;
}
- bos_total_size += bos[i]->size;
+ if ((i == 0) || (bos[i] != bos[0]))
+ bos_total_size += bos[i]->size;
}
if (bos_total_size < layout.total_size) {
@@ -926,6 +986,23 @@ const struct sde_format *sde_get_sde_format_ext(
map_size = ARRAY_SIZE(sde_format_map_ubwc);
DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED", format);
break;
+ case DRM_FORMAT_MOD_QCOM_DX:
+ map = sde_format_map_p010;
+ map_size = ARRAY_SIZE(sde_format_map_p010);
+ DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_DX", format);
+ break;
+ case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED):
+ map = sde_format_map_p010_ubwc;
+ map_size = ARRAY_SIZE(sde_format_map_p010_ubwc);
+ DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED/DX", format);
+ break;
+ case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED |
+ DRM_FORMAT_MOD_QCOM_TIGHT):
+ map = sde_format_map_tp10_ubwc;
+ map_size = ARRAY_SIZE(sde_format_map_tp10_ubwc);
+ DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED/DX/TIGHT",
+ format);
+ break;
default:
DRM_ERROR("unsupported format modifier %llX\n", mod0);
return NULL;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 17b678cfca46..4f84e31db5f6 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -405,6 +405,38 @@ static struct sde_prop_type vbif_prop[] = {
/*************************************************************
* static API list
*************************************************************/
+
+/**
+ * _sde_copy_formats - copy formats from src_list to dst_list
+ * @dst_list: pointer to destination list where to copy formats
+ * @dst_list_size: size of destination list
+ * @dst_list_pos: starting position on the list where to copy formats
+ * @src_list: pointer to source list where to copy formats from
+ * @src_list_size: size of source list
+ * Return: number of elements populated
+ */
+static uint32_t _sde_copy_formats(
+ struct sde_format_extended *dst_list,
+ uint32_t dst_list_size,
+ uint32_t dst_list_pos,
+ const struct sde_format_extended *src_list,
+ uint32_t src_list_size)
+{
+ uint32_t cur_pos, i;
+
+ if (!dst_list || !src_list || (dst_list_pos >= (dst_list_size - 1)))
+ return 0;
+
+ for (i = 0, cur_pos = dst_list_pos;
+ (cur_pos < (dst_list_size - 1)) && src_list[i].fourcc_format
+ && (i < src_list_size); ++i, ++cur_pos)
+ dst_list[cur_pos] = src_list[i];
+
+ dst_list[cur_pos].fourcc_format = 0;
+
+ return i;
+}
+
static int _parse_dt_u32_handler(struct device_node *np,
char *prop_name, u32 *offsets, int len, bool mandatory)
{
@@ -658,7 +690,7 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = MAX_SSPP_DOWNSCALE;
sspp->id = SSPP_VIG0 + *vig_count;
sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + *vig_count;
- sblk->format_list = plane_formats_yuv;
+ sspp->type = SSPP_TYPE_VIG;
set_bit(SDE_SSPP_QOS, &sspp->features);
(*vig_count)++;
@@ -728,7 +760,7 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = MAX_SSPP_DOWNSCALE;
sspp->id = SSPP_RGB0 + *rgb_count;
sspp->clk_ctrl = SDE_CLK_CTRL_RGB0 + *rgb_count;
- sblk->format_list = plane_formats;
+ sspp->type = SSPP_TYPE_RGB;
set_bit(SDE_SSPP_QOS, &sspp->features);
(*rgb_count)++;
@@ -768,7 +800,7 @@ static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sspp->id = SSPP_CURSOR0 + *cursor_count;
sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count;
- sblk->format_list = plane_formats;
+ sspp->type = SSPP_TYPE_CURSOR;
(*cursor_count)++;
snprintf(sspp->name, sizeof(sspp->name), "cursor%d", *cursor_count-1);
}
@@ -781,7 +813,7 @@ static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sspp->id = SSPP_DMA0 + *dma_count;
sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count;
- sblk->format_list = plane_formats;
+ sspp->type = SSPP_TYPE_DMA;
set_bit(SDE_SSPP_QOS, &sspp->features);
(*dma_count)++;
snprintf(sspp->name, sizeof(sspp->name), "dma%d", *dma_count-1);
@@ -1258,7 +1290,6 @@ static int sde_wb_parse_dt(struct device_node *np,
wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i);
wb->vbif_idx = VBIF_NRT;
wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0);
- wb->format_list = wb2_formats;
if (!prop_exists[WB_LEN])
wb->len = DEFAULT_SDE_HW_BLOCK_LEN;
sblk->maxlinewidth = sde_cfg->max_wb_linewidth;
@@ -1988,9 +2019,124 @@ end:
return rc;
}
-static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg,
+static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg,
uint32_t hw_rev)
{
+ int i, rc = 0;
+ uint32_t dma_list_size, vig_list_size, wb2_list_size;
+ uint32_t cursor_list_size = 0;
+ struct sde_sspp_sub_blks *sblk;
+ uint32_t index = 0;
+
+ if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_300)) {
+ cursor_list_size = ARRAY_SIZE(cursor_formats);
+ sde_cfg->cursor_formats = kcalloc(cursor_list_size,
+ sizeof(struct sde_format_extended), GFP_KERNEL);
+ if (!sde_cfg->cursor_formats) {
+ rc = -ENOMEM;
+ goto end;
+ }
+ index = _sde_copy_formats(sde_cfg->cursor_formats,
+ cursor_list_size, 0, cursor_formats,
+ ARRAY_SIZE(cursor_formats));
+ }
+
+ dma_list_size = ARRAY_SIZE(plane_formats);
+ vig_list_size = ARRAY_SIZE(plane_formats_yuv);
+ wb2_list_size = ARRAY_SIZE(wb2_formats);
+
+ dma_list_size += ARRAY_SIZE(rgb_10bit_formats);
+ vig_list_size += ARRAY_SIZE(rgb_10bit_formats)
+ + ARRAY_SIZE(tp10_ubwc_formats)
+ + ARRAY_SIZE(p010_formats);
+ wb2_list_size += ARRAY_SIZE(rgb_10bit_formats)
+ + ARRAY_SIZE(tp10_ubwc_formats);
+
+ sde_cfg->dma_formats = kcalloc(dma_list_size,
+ sizeof(struct sde_format_extended), GFP_KERNEL);
+ if (!sde_cfg->dma_formats) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ sde_cfg->vig_formats = kcalloc(vig_list_size,
+ sizeof(struct sde_format_extended), GFP_KERNEL);
+ if (!sde_cfg->vig_formats) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ sde_cfg->wb_formats = kcalloc(wb2_list_size,
+ sizeof(struct sde_format_extended), GFP_KERNEL);
+ if (!sde_cfg->wb_formats) {
+ SDE_ERROR("failed to allocate wb format list\n");
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ index = _sde_copy_formats(sde_cfg->dma_formats, dma_list_size,
+ 0, plane_formats, ARRAY_SIZE(plane_formats));
+ index += _sde_copy_formats(sde_cfg->dma_formats, dma_list_size,
+ index, rgb_10bit_formats,
+ ARRAY_SIZE(rgb_10bit_formats));
+
+ index = _sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
+ 0, plane_formats_yuv, ARRAY_SIZE(plane_formats_yuv));
+ index += _sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
+ index, rgb_10bit_formats,
+ ARRAY_SIZE(rgb_10bit_formats));
+ index += _sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
+ index, p010_formats, ARRAY_SIZE(p010_formats));
+
+ index += _sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
+ index, tp10_ubwc_formats,
+ ARRAY_SIZE(tp10_ubwc_formats));
+
+ index = _sde_copy_formats(sde_cfg->wb_formats, wb2_list_size,
+ 0, wb2_formats, ARRAY_SIZE(wb2_formats));
+ index += _sde_copy_formats(sde_cfg->wb_formats, wb2_list_size,
+ index, rgb_10bit_formats,
+ ARRAY_SIZE(rgb_10bit_formats));
+ index += _sde_copy_formats(sde_cfg->wb_formats, wb2_list_size,
+ index, tp10_ubwc_formats,
+ ARRAY_SIZE(tp10_ubwc_formats));
+
+ for (i = 0; i < sde_cfg->sspp_count; ++i) {
+ struct sde_sspp_cfg *sspp = &sde_cfg->sspp[i];
+
+ sblk = (struct sde_sspp_sub_blks *)sspp->sblk;
+ switch (sspp->type) {
+ case SSPP_TYPE_VIG:
+ sblk->format_list = sde_cfg->vig_formats;
+ break;
+ case SSPP_TYPE_CURSOR:
+ if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_300))
+ sblk->format_list = sde_cfg->cursor_formats;
+ else
+ SDE_ERROR("invalid sspp type %d, xin id %d\n",
+ sspp->type, sspp->xin_id);
+ break;
+ case SSPP_TYPE_DMA:
+ sblk->format_list = sde_cfg->dma_formats;
+ break;
+ default:
+ SDE_ERROR("invalid sspp type %d\n", sspp->type);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+
+ for (i = 0; i < sde_cfg->wb_count; ++i)
+ sde_cfg->wb[i].format_list = sde_cfg->wb_formats;
+
+end:
+ return rc;
+}
+
+static int sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
+{
+ int rc = 0;
+
switch (hw_rev) {
case SDE_HW_VER_170:
case SDE_HW_VER_171:
@@ -1998,10 +2144,14 @@ static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg,
/* update msm8996 target here */
break;
case SDE_HW_VER_300:
+ case SDE_HW_VER_301:
case SDE_HW_VER_400:
/* update cobalt and skunk target here */
+ rc = sde_hardware_format_caps(sde_cfg, hw_rev);
break;
}
+
+ return rc;
}
void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
@@ -2040,6 +2190,11 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
}
}
+ kfree(sde_cfg->dma_formats);
+ kfree(sde_cfg->cursor_formats);
+ kfree(sde_cfg->vig_formats);
+ kfree(sde_cfg->wb_formats);
+
kfree(sde_cfg);
}
@@ -2109,7 +2264,9 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev,
if (rc)
SDE_DEBUG("virtual plane is not supported.\n");
- sde_hardware_caps(sde_cfg, hw_rev);
+ rc = sde_hardware_caps(sde_cfg, hw_rev);
+ if (rc)
+ goto end;
return sde_cfg;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index bca221d2a959..01204df48871 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -42,7 +42,8 @@
#define SDE_HW_VER_170 SDE_HW_VER(1, 7, 0) /* 8996 v1.0 */
#define SDE_HW_VER_171 SDE_HW_VER(1, 7, 1) /* 8996 v2.0 */
#define SDE_HW_VER_172 SDE_HW_VER(1, 7, 2) /* 8996 v3.0 */
-#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* cobalt v1.0 */
+#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */
+#define SDE_HW_VER_301 SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */
#define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* msmskunk v1.0 */
#define IS_MSMSKUNK_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400)
@@ -457,7 +458,8 @@ struct sde_ctl_cfg {
* @sblk: SSPP sub-blocks information
* @xin_id: bus client identifier
* @clk_ctrl clock control identifier
- *@name source pipe name
+ * @name source pipe name
+ * @type sspp type identifier
*/
struct sde_sspp_cfg {
SDE_HW_BLK_INFO;
@@ -465,6 +467,7 @@ struct sde_sspp_cfg {
u32 xin_id;
enum sde_clk_ctrl_type clk_ctrl;
char name[SSPP_NAME_SIZE];
+ u32 type;
};
/**
@@ -652,6 +655,10 @@ struct sde_vp_cfg {
* @csc_type csc or csc_10bit support.
* @has_src_split source split feature status
* @has_cdp Client driver prefetch feature status
+ * @dma_formats Supported formats for dma pipe
+ * @cursor_formats Supported formats for cursor pipe
+ * @vig_formats Supported formats for vig pipe
+ * @wb_formats Supported formats for wb
*/
struct sde_mdss_cfg {
u32 hwversion;
@@ -704,6 +711,11 @@ struct sde_mdss_cfg {
u32 vp_count;
struct sde_vp_cfg vp[MAX_BLOCKS];
+
+ struct sde_format_extended *dma_formats;
+ struct sde_format_extended *cursor_formats;
+ struct sde_format_extended *vig_formats;
+ struct sde_format_extended *wb_formats;
};
struct sde_mdss_hw_cfg_handler {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
index 296694422653..dbc8981a7f8f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.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
@@ -16,17 +16,17 @@ static const struct sde_format_extended plane_formats[] = {
{DRM_FORMAT_ARGB8888, 0},
{DRM_FORMAT_ABGR8888, 0},
{DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGRA8888, 0},
{DRM_FORMAT_XRGB8888, 0},
{DRM_FORMAT_RGBX8888, 0},
{DRM_FORMAT_BGRX8888, 0},
{DRM_FORMAT_XBGR8888, 0},
- {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_RGB888, 0},
{DRM_FORMAT_BGR888, 0},
{DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGR565, 0},
{DRM_FORMAT_ARGB1555, 0},
{DRM_FORMAT_ABGR1555, 0},
@@ -52,16 +52,16 @@ static const struct sde_format_extended plane_formats_yuv[] = {
{DRM_FORMAT_ABGR8888, 0},
{DRM_FORMAT_RGBA8888, 0},
{DRM_FORMAT_BGRX8888, 0},
- {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGRA8888, 0},
{DRM_FORMAT_XRGB8888, 0},
{DRM_FORMAT_XBGR8888, 0},
{DRM_FORMAT_RGBX8888, 0},
- {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_RGB888, 0},
{DRM_FORMAT_BGR888, 0},
{DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGR565, 0},
{DRM_FORMAT_ARGB1555, 0},
{DRM_FORMAT_ABGR1555, 0},
@@ -94,13 +94,33 @@ static const struct sde_format_extended plane_formats_yuv[] = {
{0, 0},
};
+static const struct sde_format_extended cursor_formats[] = {
+ {DRM_FORMAT_ARGB8888, 0},
+ {DRM_FORMAT_ABGR8888, 0},
+ {DRM_FORMAT_RGBA8888, 0},
+ {DRM_FORMAT_BGRA8888, 0},
+ {DRM_FORMAT_XRGB8888, 0},
+ {DRM_FORMAT_ARGB1555, 0},
+ {DRM_FORMAT_ABGR1555, 0},
+ {DRM_FORMAT_RGBA5551, 0},
+ {DRM_FORMAT_BGRA5551, 0},
+ {DRM_FORMAT_ARGB4444, 0},
+ {DRM_FORMAT_ABGR4444, 0},
+ {DRM_FORMAT_RGBA4444, 0},
+ {DRM_FORMAT_BGRA4444, 0},
+ {0, 0},
+};
+
static const struct sde_format_extended wb2_formats[] = {
{DRM_FORMAT_RGB565, 0},
+ {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_RGB888, 0},
{DRM_FORMAT_ARGB8888, 0},
{DRM_FORMAT_RGBA8888, 0},
+ {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_XRGB8888, 0},
{DRM_FORMAT_RGBX8888, 0},
+ {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_ARGB1555, 0},
{DRM_FORMAT_RGBA5551, 0},
{DRM_FORMAT_XRGB1555, 0},
@@ -127,8 +147,31 @@ static const struct sde_format_extended wb2_formats[] = {
{DRM_FORMAT_YUV420, 0},
{DRM_FORMAT_NV12, 0},
+ {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_NV16, 0},
{DRM_FORMAT_YUYV, 0},
{0, 0},
};
+
+static const struct sde_format_extended rgb_10bit_formats[] = {
+ {DRM_FORMAT_BGRA1010102, 0},
+ {DRM_FORMAT_BGRX1010102, 0},
+ {DRM_FORMAT_RGBA1010102, 0},
+ {DRM_FORMAT_RGBX1010102, 0},
+ {DRM_FORMAT_ABGR2101010, 0},
+ {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_XBGR2101010, 0},
+ {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_ARGB2101010, 0},
+ {DRM_FORMAT_XRGB2101010, 0},
+};
+
+static const struct sde_format_extended p010_formats[] = {
+ {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_DX},
+};
+
+static const struct sde_format_extended tp10_ubwc_formats[] = {
+ {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED |
+ DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT},
+};
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index dcba248d27b0..7a5e7ad79f0f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -41,11 +41,18 @@
#define SDE_MAX_DE_CURVES 3
#endif
-#define SDE_FORMAT_FLAG_YUV (1 << 0)
-#define SDE_FORMAT_FLAG_DX (1 << 1)
+enum sde_format_flags {
+ SDE_FORMAT_FLAG_YUV_BIT,
+ SDE_FORMAT_FLAG_DX_BIT,
+ SDE_FORMAT_FLAG_BIT_MAX,
+};
-#define SDE_FORMAT_IS_YUV(X) ((X)->flag & SDE_FORMAT_FLAG_YUV)
-#define SDE_FORMAT_IS_DX(X) ((X)->flag & SDE_FORMAT_FLAG_DX)
+#define SDE_FORMAT_FLAG_YUV BIT(SDE_FORMAT_FLAG_YUV_BIT)
+#define SDE_FORMAT_FLAG_DX BIT(SDE_FORMAT_FLAG_DX_BIT)
+#define SDE_FORMAT_IS_YUV(X) \
+ (test_bit(SDE_FORMAT_FLAG_YUV_BIT, (X)->flag))
+#define SDE_FORMAT_IS_DX(X) \
+ (test_bit(SDE_FORMAT_FLAG_DX_BIT, (X)->flag))
#define SDE_FORMAT_IS_LINEAR(X) ((X)->fetch_mode == SDE_FETCH_LINEAR)
#define SDE_FORMAT_IS_UBWC(X) ((X)->fetch_mode == SDE_FETCH_UBWC)
@@ -357,7 +364,7 @@ struct sde_format {
u8 alpha_enable;
u8 num_planes;
enum sde_fetch_type fetch_mode;
- u32 flag;
+ DECLARE_BITMAP(flag, SDE_FORMAT_FLAG_BIT_MAX);
u16 tile_width;
u16 tile_height;
};
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 45a87456e5ec..031493aa42b8 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -601,6 +601,8 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.mode_valid = sde_hdmi_mode_valid,
.get_info = sde_hdmi_get_info,
.set_property = sde_hdmi_set_property,
+ .get_property = sde_hdmi_get_property,
+ .pre_kickoff = sde_hdmi_pre_kickoff,
};
struct msm_display_info info = {0};
struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
index 82d3e28918fd..7e4f24ae7de8 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -4,6 +4,7 @@
struct nvkm_alarm {
struct list_head head;
+ struct list_head exec;
u64 timestamp;
void (*func)(struct nvkm_alarm *);
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
index 79fcdb43e174..46033909d950 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -50,7 +50,8 @@ nvkm_timer_alarm_trigger(struct nvkm_timer *tmr)
/* Move to completed list. We'll drop the lock before
* executing the callback so it can reschedule itself.
*/
- list_move_tail(&alarm->head, &exec);
+ list_del_init(&alarm->head);
+ list_add(&alarm->exec, &exec);
}
/* Shut down interrupt if no more pending alarms. */
@@ -59,8 +60,8 @@ nvkm_timer_alarm_trigger(struct nvkm_timer *tmr)
spin_unlock_irqrestore(&tmr->lock, flags);
/* Execute completed callbacks. */
- list_for_each_entry_safe(alarm, atemp, &exec, head) {
- list_del_init(&alarm->head);
+ list_for_each_entry_safe(alarm, atemp, &exec, exec) {
+ list_del(&alarm->exec);
alarm->func(alarm);
}
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index b6a0806b06bf..a1c68e6a689e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -368,6 +368,8 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
return fifo_state->static_buffer;
else {
fifo_state->dynamic_buffer = vmalloc(bytes);
+ if (!fifo_state->dynamic_buffer)
+ goto out_err;
return fifo_state->dynamic_buffer;
}
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index c9c04ccccdd9..027987023400 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -1288,11 +1288,14 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
int ret;
uint32_t size;
- uint32_t backup_handle;
+ uint32_t backup_handle = 0;
if (req->multisample_count != 0)
return -EINVAL;
+ if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS)
+ return -EINVAL;
+
if (unlikely(vmw_user_surface_size == 0))
vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
128;
@@ -1328,12 +1331,16 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
&res->backup,
&user_srf->backup_base);
- if (ret == 0 && res->backup->base.num_pages * PAGE_SIZE <
- res->backup_size) {
- DRM_ERROR("Surface backup buffer is too small.\n");
- vmw_dmabuf_unreference(&res->backup);
- ret = -EINVAL;
- goto out_unlock;
+ if (ret == 0) {
+ if (res->backup->base.num_pages * PAGE_SIZE <
+ res->backup_size) {
+ DRM_ERROR("Surface backup buffer is too small.\n");
+ vmw_dmabuf_unreference(&res->backup);
+ ret = -EINVAL;
+ goto out_unlock;
+ } else {
+ backup_handle = req->buffer_handle;
+ }
}
} else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer)
ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 6bf89d8f3741..b9d1e5c58ec5 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -74,9 +74,9 @@ static const int int_time_mapping[] = {100000, 50000, 200000, 400000};
static const struct reg_field reg_field_it =
REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4);
static const struct reg_field reg_field_als_intr =
- REG_FIELD(LTR501_INTR, 0, 0);
-static const struct reg_field reg_field_ps_intr =
REG_FIELD(LTR501_INTR, 1, 1);
+static const struct reg_field reg_field_ps_intr =
+ REG_FIELD(LTR501_INTR, 0, 0);
static const struct reg_field reg_field_als_rate =
REG_FIELD(LTR501_ALS_MEAS_RATE, 0, 2);
static const struct reg_field reg_field_ps_rate =
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index bf0bd7e03aff..9e6d1cdb7fcd 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -40,9 +40,9 @@
#define AS3935_AFE_PWR_BIT BIT(0)
#define AS3935_INT 0x03
-#define AS3935_INT_MASK 0x07
+#define AS3935_INT_MASK 0x0f
#define AS3935_EVENT_INT BIT(3)
-#define AS3935_NOISE_INT BIT(1)
+#define AS3935_NOISE_INT BIT(0)
#define AS3935_DATA 0x07
#define AS3935_DATA_MASK 0x3F
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index e6b7556d5221..cbc4216091c9 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -2088,8 +2088,10 @@ send_last:
ret = qib_get_rwqe(qp, 1);
if (ret < 0)
goto nack_op_err;
- if (!ret)
+ if (!ret) {
+ qib_put_ss(&qp->r_sge);
goto rnr_nak;
+ }
wc.ex.imm_data = ohdr->u.rc.imm_data;
hdrsize += 4;
wc.wc_flags = IB_WC_WITH_IMM;
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 1a2b2620421e..6f4dc0fd2ca3 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1122,8 +1122,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons
* Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
* Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
@@ -1529,6 +1531,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
},
},
{
+ /* Fujitsu LIFEBOOK E546 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E546"),
+ },
+ },
+ {
/* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -1550,6 +1559,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
},
},
{
+ /* Fujitsu LIFEBOOK E557 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E557"),
+ },
+ },
+ {
/* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
index daa35845fc0a..93c9c3c373b8 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
@@ -1495,7 +1495,7 @@ static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
return retval;
}
-static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
+static int synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
struct synaptics_rmi4_fn_desc *fd,
unsigned int intr_count)
{
@@ -1503,6 +1503,12 @@ static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
unsigned char intr_offset;
fhandler->intr_reg_num = (intr_count + 7) / 8;
+ if (fhandler->intr_reg_num >= MAX_INTR_REGISTERS) {
+ fhandler->intr_reg_num = 0;
+ fhandler->num_of_data_sources = 0;
+ fhandler->intr_mask = 0;
+ return -EINVAL;
+ }
if (fhandler->intr_reg_num != 0)
fhandler->intr_reg_num -= 1;
@@ -1515,7 +1521,7 @@ static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
ii++)
fhandler->intr_mask |= 1 << ii;
- return;
+ return 0;
}
static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
@@ -1523,12 +1529,17 @@ static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_fn_desc *fd,
unsigned int intr_count)
{
+ int retval;
+
fhandler->fn_number = fd->fn_number;
fhandler->num_of_data_sources = fd->intr_src_count;
fhandler->data = NULL;
fhandler->extra = NULL;
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ if (retval < 0)
+ return retval;
+
rmi4_data->f01_query_base_addr = fd->query_base_addr;
rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr;
@@ -1653,7 +1664,9 @@ static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
if (retval < 0)
return retval;
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ if (retval < 0)
+ return retval;
abs_data_size = query[5] & MASK_2BIT;
abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0));
@@ -1934,7 +1947,9 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
if (retval < 0)
goto free_function_handler_mem;
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ if (retval < 0)
+ return retval;
/* Allocate memory for finger data storage space */
fhandler->data_size = num_of_fingers * size_of_2d_data;
@@ -2092,7 +2107,9 @@ static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data,
fhandler->fn_number = fd->fn_number;
fhandler->num_of_data_sources = fd->intr_src_count;
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+ if (retval < 0)
+ return retval;
retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler);
if (retval < 0)
@@ -2491,6 +2508,8 @@ flash_prog_mode:
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Number of interrupt registers = %d\n",
__func__, rmi4_data->num_of_intr_regs);
+ if (rmi4_data->num_of_intr_regs >= MAX_INTR_REGISTERS)
+ return -EINVAL;
retval = synaptics_rmi4_reg_read(rmi4_data,
rmi4_data->f01_query_base_addr,
diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c
index 3e2c13b9cbbe..3c2e28eaa4f9 100644
--- a/drivers/media/platform/msm/ais/msm.c
+++ b/drivers/media/platform/msm/ais/msm.c
@@ -283,22 +283,47 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id)
struct msm_session *session = NULL;
struct msm_stream *stream = NULL;
unsigned long flags;
+ int try_count = 0;
session = msm_queue_find(msm_session_q, struct msm_session,
list, __msm_queue_find_session, &session_id);
+
if (!session)
return;
- stream = msm_queue_find(&session->stream_q, struct msm_stream,
- list, __msm_queue_find_stream, &stream_id);
- if (!stream)
- return;
- spin_lock_irqsave(&(session->stream_q.lock), flags);
- list_del_init(&stream->list);
- session->stream_q.len--;
- kfree(stream);
- stream = NULL;
- spin_unlock_irqrestore(&(session->stream_q.lock), flags);
+ while (1) {
+
+ if (try_count > 5) {
+ pr_err("%s : not able to delete stream %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ write_lock(&session->stream_rwlock);
+ try_count++;
+ stream = msm_queue_find(&session->stream_q, struct msm_stream,
+ list, __msm_queue_find_stream, &stream_id);
+
+ if (!stream) {
+ write_unlock(&session->stream_rwlock);
+ return;
+ }
+
+ if (msm_vb2_get_stream_state(stream) != 1) {
+ write_unlock(&session->stream_rwlock);
+ continue;
+ }
+
+ spin_lock_irqsave(&(session->stream_q.lock), flags);
+ list_del_init(&stream->list);
+ session->stream_q.len--;
+ kfree(stream);
+ stream = NULL;
+ spin_unlock_irqrestore(&(session->stream_q.lock), flags);
+ write_unlock(&session->stream_rwlock);
+ break;
+ }
+
}
EXPORT_SYMBOL(msm_delete_stream);
@@ -446,6 +471,7 @@ int msm_create_session(unsigned int session_id, struct video_device *vdev)
mutex_init(&session->lock);
mutex_init(&session->lock_q);
mutex_init(&session->close_lock);
+ rwlock_init(&session->stream_rwlock);
return 0;
}
EXPORT_SYMBOL(msm_create_session);
@@ -1040,17 +1066,25 @@ static struct v4l2_file_operations msm_fops = {
#endif
};
-struct msm_stream *msm_get_stream(unsigned int session_id,
- unsigned int stream_id)
+struct msm_session *msm_get_session(unsigned int session_id)
{
struct msm_session *session;
- struct msm_stream *stream;
session = msm_queue_find(msm_session_q, struct msm_session,
list, __msm_queue_find_session, &session_id);
if (!session)
return ERR_PTR(-EINVAL);
+ return session;
+}
+EXPORT_SYMBOL(msm_get_session);
+
+
+struct msm_stream *msm_get_stream(struct msm_session *session,
+ unsigned int stream_id)
+{
+ struct msm_stream *stream;
+
stream = msm_queue_find(&session->stream_q, struct msm_stream,
list, __msm_queue_find_stream, &stream_id);
@@ -1108,6 +1142,34 @@ struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q)
}
EXPORT_SYMBOL(msm_get_stream_from_vb2q);
+struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q)
+{
+ struct msm_session *session;
+ struct msm_stream *stream;
+ unsigned long flags1;
+ unsigned long flags2;
+
+ spin_lock_irqsave(&msm_session_q->lock, flags1);
+ list_for_each_entry(session, &(msm_session_q->list), list) {
+ spin_lock_irqsave(&(session->stream_q.lock), flags2);
+ list_for_each_entry(
+ stream, &(session->stream_q.list), list) {
+ if (stream->vb2_q == q) {
+ spin_unlock_irqrestore
+ (&(session->stream_q.lock), flags2);
+ spin_unlock_irqrestore
+ (&msm_session_q->lock, flags1);
+ return session;
+ }
+ }
+ spin_unlock_irqrestore(&(session->stream_q.lock), flags2);
+ }
+ spin_unlock_irqrestore(&msm_session_q->lock, flags1);
+ return NULL;
+}
+EXPORT_SYMBOL(msm_get_session_from_vb2q);
+
+
#ifdef CONFIG_COMPAT
long msm_copy_camera_private_ioctl_args(unsigned long arg,
struct msm_camera_private_ioctl_arg *k_ioctl,
diff --git a/drivers/media/platform/msm/ais/msm.h b/drivers/media/platform/msm/ais/msm.h
index d8b2d5871fc2..5d456310c301 100644
--- a/drivers/media/platform/msm/ais/msm.h
+++ b/drivers/media/platform/msm/ais/msm.h
@@ -114,6 +114,7 @@ struct msm_session {
struct mutex lock;
struct mutex lock_q;
struct mutex close_lock;
+ rwlock_t stream_rwlock;
};
static inline bool msm_is_daemon_present(void)
@@ -131,11 +132,13 @@ int msm_create_stream(unsigned int session_id,
void msm_delete_stream(unsigned int session_id, unsigned int stream_id);
int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id);
void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id);
-struct msm_stream *msm_get_stream(unsigned int session_id,
+struct msm_session *msm_get_session(unsigned int session_id);
+struct msm_stream *msm_get_stream(struct msm_session *session,
unsigned int stream_id);
struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
unsigned int stream_id);
struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
+struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q);
struct msm_session *msm_session_find(unsigned int session_id);
#ifdef CONFIG_COMPAT
long msm_copy_camera_private_ioctl_args(unsigned long arg,
diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c
index 2c1c0a34389a..36aa3f62fbec 100644
--- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c
@@ -44,17 +44,25 @@ static int msm_vb2_queue_setup(struct vb2_queue *q,
static int msm_vb2_buf_init(struct vb2_buffer *vb)
{
struct msm_stream *stream;
+ struct msm_session *session;
struct msm_vb2_buffer *msm_vb2_buf;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ session = msm_get_session_from_vb2q(vb->vb2_queue);
+ if (IS_ERR_OR_NULL(session))
+ return -EINVAL;
+
+ read_lock(&session->stream_rwlock);
+
stream = msm_get_stream_from_vb2q(vb->vb2_queue);
if (!stream) {
pr_err("%s: Couldn't find stream\n", __func__);
+ read_unlock(&session->stream_rwlock);
return -EINVAL;
}
msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
msm_vb2_buf->in_freeq = 0;
-
+ read_unlock(&session->stream_rwlock);
return 0;
}
@@ -62,6 +70,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb)
{
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
+ struct msm_session *session;
unsigned long flags;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -71,21 +80,30 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb)
return;
}
+ session = msm_get_session_from_vb2q(vb->vb2_queue);
+ if (IS_ERR_OR_NULL(session))
+ return;
+
+ read_lock(&session->stream_rwlock);
+
stream = msm_get_stream_from_vb2q(vb->vb2_queue);
if (!stream) {
pr_err("%s:%d] NULL stream", __func__, __LINE__);
+ read_unlock(&session->stream_rwlock);
return;
}
spin_lock_irqsave(&stream->stream_lock, flags);
list_add_tail(&msm_vb2->list, &stream->queued_list);
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
}
static void msm_vb2_buf_finish(struct vb2_buffer *vb)
{
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
+ struct msm_session *session;
unsigned long flags;
struct msm_vb2_buffer *msm_vb2_entry, *temp;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -96,9 +114,16 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb)
return;
}
+ session = msm_get_session_from_vb2q(vb->vb2_queue);
+ if (IS_ERR_OR_NULL(session))
+ return;
+
+ read_lock(&session->stream_rwlock);
+
stream = msm_get_stream_from_vb2q(vb->vb2_queue);
if (!stream) {
pr_err("%s:%d] NULL stream", __func__, __LINE__);
+ read_unlock(&session->stream_rwlock);
return;
}
@@ -111,18 +136,27 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb)
}
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
}
static void msm_vb2_stop_stream(struct vb2_queue *q)
{
struct msm_vb2_buffer *msm_vb2, *temp;
struct msm_stream *stream;
+ struct msm_session *session;
unsigned long flags;
struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ session = msm_get_session_from_vb2q(q);
+ if (IS_ERR_OR_NULL(session))
+ return;
+
+ read_lock(&session->stream_rwlock);
+
stream = msm_get_stream_from_vb2q(q);
if (!stream) {
pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__);
+ read_unlock(&session->stream_rwlock);
return;
}
@@ -142,8 +176,28 @@ static void msm_vb2_stop_stream(struct vb2_queue *q)
msm_vb2->in_freeq = 0;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
}
+int msm_vb2_get_stream_state(struct msm_stream *stream)
+{
+ struct msm_vb2_buffer *msm_vb2, *temp;
+ unsigned long flags;
+ int rc = 1;
+
+ spin_lock_irqsave(&stream->stream_lock, flags);
+ list_for_each_entry_safe(msm_vb2, temp, &(stream->queued_list), list) {
+ if (msm_vb2->in_freeq != 0) {
+ rc = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&stream->stream_lock, flags);
+ return rc;
+}
+EXPORT_SYMBOL(msm_vb2_get_stream_state);
+
+
static struct vb2_ops msm_vb2_get_q_op = {
.queue_setup = msm_vb2_queue_setup,
.buf_init = msm_vb2_buf_init,
@@ -199,13 +253,22 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id,
{
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+ struct msm_session *session;
struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
- stream = msm_get_stream(session_id, stream_id);
- if (IS_ERR_OR_NULL(stream))
+ session = msm_get_session(session_id);
+ if (IS_ERR_OR_NULL(session))
return NULL;
+ read_lock(&session->stream_rwlock);
+
+ stream = msm_get_stream(session, stream_id);
+ if (IS_ERR_OR_NULL(stream)) {
+ read_unlock(&session->stream_rwlock);
+ return NULL;
+ }
+
spin_lock_irqsave(&stream->stream_lock, flags);
if (!stream->vb2_q) {
@@ -228,6 +291,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id,
vb2_v4l2_buf = NULL;
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
return vb2_v4l2_buf;
}
@@ -236,12 +300,22 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id,
{
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+ struct msm_session *session;
struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
- stream = msm_get_stream(session_id, stream_id);
- if (IS_ERR_OR_NULL(stream))
+ session = msm_get_session(session_id);
+ if (IS_ERR_OR_NULL(session))
+ return NULL;
+
+ read_lock(&session->stream_rwlock);
+
+ stream = msm_get_stream(session, stream_id);
+
+ if (IS_ERR_OR_NULL(stream)) {
+ read_unlock(&session->stream_rwlock);
return NULL;
+ }
spin_lock_irqsave(&stream->stream_lock, flags);
@@ -263,6 +337,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id,
vb2_v4l2_buf = NULL;
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
return vb2_v4l2_buf;
}
@@ -270,15 +345,24 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id,
unsigned int stream_id)
{
struct msm_stream *stream;
+ struct msm_session *session;
struct msm_vb2_buffer *msm_vb2;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
int rc = 0;
unsigned long flags;
- stream = msm_get_stream(session_id, stream_id);
- if (IS_ERR_OR_NULL(stream))
+ session = msm_get_session(session_id);
+ if (IS_ERR_OR_NULL(session))
return -EINVAL;
+ read_lock(&session->stream_rwlock);
+
+ stream = msm_get_stream(session, stream_id);
+ if (IS_ERR_OR_NULL(stream)) {
+ read_unlock(&session->stream_rwlock);
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
@@ -306,6 +390,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id,
rc = -EINVAL;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
return rc;
}
@@ -317,11 +402,21 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id,
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+ struct msm_session *session;
int rc = 0;
- stream = msm_get_stream(session_id, stream_id);
- if (IS_ERR_OR_NULL(stream))
+ session = msm_get_session(session_id);
+ if (IS_ERR_OR_NULL(session))
return -EINVAL;
+
+ read_lock(&session->stream_rwlock);
+
+ stream = msm_get_stream(session, stream_id);
+ if (IS_ERR_OR_NULL(stream)) {
+ read_unlock(&session->stream_rwlock);
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
@@ -353,6 +448,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id,
rc = -EINVAL;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
return rc;
}
@@ -361,14 +457,23 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
{
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+ struct msm_session *session;
struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
long rc = -EINVAL;
- stream = msm_get_stream(session_id, stream_id);
- if (IS_ERR_OR_NULL(stream))
+ session = msm_get_session(session_id);
+ if (IS_ERR_OR_NULL(session))
return rc;
+ read_lock(&session->stream_rwlock);
+
+ stream = msm_get_stream(session, stream_id);
+ if (IS_ERR_OR_NULL(stream)) {
+ read_unlock(&session->stream_rwlock);
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&stream->stream_lock, flags);
if (!stream->vb2_q) {
@@ -394,6 +499,7 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
return rc;
}
EXPORT_SYMBOL(msm_vb2_return_buf_by_idx);
@@ -404,10 +510,20 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id)
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+ struct msm_session *session;
+
+ session = msm_get_session(session_id);
+ if (IS_ERR_OR_NULL(session))
+ return -EINVAL;
- stream = msm_get_stream(session_id, stream_id);
- if (IS_ERR_OR_NULL(stream))
+ read_lock(&session->stream_rwlock);
+
+ stream = msm_get_stream(session, stream_id);
+ if (IS_ERR_OR_NULL(stream)) {
+ read_unlock(&session->stream_rwlock);
return -EINVAL;
+ }
+
spin_lock_irqsave(&stream->stream_lock, flags);
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
@@ -416,6 +532,7 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id)
msm_vb2->in_freeq = 0;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
+ read_unlock(&session->stream_rwlock);
return 0;
}
diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h
index 3dbb21332857..0f57112e82f2 100644
--- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h
+++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h
@@ -68,5 +68,6 @@ struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void);
int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd);
long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
uint32_t index);
+int msm_vb2_get_stream_state(struct msm_stream *stream);
#endif /*_MSM_VB_H */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index e2f068a21c28..0352ae9cb595 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -2296,6 +2296,8 @@ static void msm_isp_input_disable(struct vfe_device *vfe_dev, int cmd_type)
ms_res->src_info[src_info->dual_hw_ms_info.index] =
NULL;
ms_res->num_src--;
+ if (ms_res->num_src == 0)
+ ms_res->dual_sync_mode = MSM_ISP_DUAL_CAM_ASYNC;
src_info->dual_hw_ms_info.sync_state =
MSM_ISP_DUAL_CAM_ASYNC;
src_info->dual_hw_type = DUAL_NONE;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index 5376e1e4b6a4..491b8d31935a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -1144,13 +1144,13 @@ static long msm_flash_subdev_do_ioctl(
sd = vdev_to_v4l2_subdev(vdev);
u32 = (struct msm_flash_cfg_data_t32 *)arg;
- flash_data.cfg_type = u32->cfg_type;
- for (i = 0; i < MAX_LED_TRIGGERS; i++) {
- flash_data.flash_current[i] = u32->flash_current[i];
- flash_data.flash_duration[i] = u32->flash_duration[i];
- }
switch (cmd) {
case VIDIOC_MSM_FLASH_CFG32:
+ flash_data.cfg_type = u32->cfg_type;
+ for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+ flash_data.flash_current[i] = u32->flash_current[i];
+ flash_data.flash_duration[i] = u32->flash_duration[i];
+ }
cmd = VIDIOC_MSM_FLASH_CFG;
switch (flash_data.cfg_type) {
case CFG_FLASH_OFF:
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c
index b3e5dc7f9cb8..c5cdee1bf706 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -520,14 +520,16 @@ int32_t msm_camera_tz_i2c_power_up(
msm_camera_tz_get_ta_handle(),
sensor_id,
&sensor_secure);
- if (!rc && sensor_secure)
+ if (!rc && sensor_secure) {
/* Sensor validated by TA*/
sensor_info[sensor_id].ready++;
+ msm_camera_tz_unlock();
+ }
else {
+ msm_camera_tz_unlock();
msm_camera_tz_unload_ta();
rc = -EFAULT;
}
- msm_camera_tz_unlock();
}
} else
rc = -EFAULT;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
index c94ee509631f..bfb15846e73c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
@@ -774,11 +774,10 @@ static long msm_ois_subdev_do_ioctl(
u32 = (struct msm_ois_cfg_data32 *)arg;
parg = arg;
- ois_data.cfgtype = u32->cfgtype;
-
switch (cmd) {
case VIDIOC_MSM_OIS_CFG32:
cmd = VIDIOC_MSM_OIS_CFG;
+ ois_data.cfgtype = u32->cfgtype;
switch (u32->cfgtype) {
case CFG_OIS_CONTROL:
@@ -812,7 +811,6 @@ static long msm_ois_subdev_do_ioctl(
settings.reg_setting =
compat_ptr(settings32.reg_setting);
- ois_data.cfgtype = u32->cfgtype;
ois_data.cfg.settings = &settings;
parg = &ois_data;
break;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 62980f345f60..42519be35aa9 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -984,6 +984,7 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr)
{
int i, size, ret = 0;
char name[32];
+ struct sched_param param = { .sched_priority = 5 };
size = sizeof(struct sde_rot_queue) * mgr->queue_count;
mgr->commitq = devm_kzalloc(mgr->device, size, GFP_KERNEL);
@@ -994,11 +995,21 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr)
snprintf(name, sizeof(name), "rot_commitq_%d_%d",
mgr->device->id, i);
SDEROT_DBG("work queue name=%s\n", name);
- mgr->commitq[i].rot_work_queue =
- alloc_ordered_workqueue("%s",
- WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
- if (!mgr->commitq[i].rot_work_queue) {
+ init_kthread_worker(&mgr->commitq[i].rot_kw);
+ mgr->commitq[i].rot_thread = kthread_run(kthread_worker_fn,
+ &mgr->commitq[i].rot_kw, name);
+ if (IS_ERR(mgr->commitq[i].rot_thread)) {
ret = -EPERM;
+ mgr->commitq[i].rot_thread = NULL;
+ break;
+ }
+
+ ret = sched_setscheduler(mgr->commitq[i].rot_thread,
+ SCHED_FIFO, &param);
+ if (ret) {
+ SDEROT_ERR(
+ "failed to set kthread priority for commitq %d\n",
+ ret);
break;
}
@@ -1015,10 +1026,21 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr)
snprintf(name, sizeof(name), "rot_doneq_%d_%d",
mgr->device->id, i);
SDEROT_DBG("work queue name=%s\n", name);
- mgr->doneq[i].rot_work_queue = alloc_ordered_workqueue("%s",
- WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
- if (!mgr->doneq[i].rot_work_queue) {
+ init_kthread_worker(&mgr->doneq[i].rot_kw);
+ mgr->doneq[i].rot_thread = kthread_run(kthread_worker_fn,
+ &mgr->doneq[i].rot_kw, name);
+ if (IS_ERR(mgr->doneq[i].rot_thread)) {
ret = -EPERM;
+ mgr->doneq[i].rot_thread = NULL;
+ break;
+ }
+
+ ret = sched_setscheduler(mgr->doneq[i].rot_thread,
+ SCHED_FIFO, &param);
+ if (ret) {
+ SDEROT_ERR(
+ "failed to set kthread priority for doneq %d\n",
+ ret);
break;
}
@@ -1034,18 +1056,20 @@ static void sde_rotator_deinit_queue(struct sde_rot_mgr *mgr)
if (mgr->commitq) {
for (i = 0; i < mgr->queue_count; i++) {
- if (mgr->commitq[i].rot_work_queue)
- destroy_workqueue(
- mgr->commitq[i].rot_work_queue);
+ if (mgr->commitq[i].rot_thread) {
+ flush_kthread_worker(&mgr->commitq[i].rot_kw);
+ kthread_stop(mgr->commitq[i].rot_thread);
+ }
}
devm_kfree(mgr->device, mgr->commitq);
mgr->commitq = NULL;
}
if (mgr->doneq) {
for (i = 0; i < mgr->queue_count; i++) {
- if (mgr->doneq[i].rot_work_queue)
- destroy_workqueue(
- mgr->doneq[i].rot_work_queue);
+ if (mgr->doneq[i].rot_thread) {
+ flush_kthread_worker(&mgr->doneq[i].rot_kw);
+ kthread_stop(mgr->doneq[i].rot_thread);
+ }
}
devm_kfree(mgr->device, mgr->doneq);
mgr->doneq = NULL;
@@ -1166,7 +1190,7 @@ void sde_rotator_queue_request(struct sde_rot_mgr *mgr,
if (entry->item.ts)
entry->item.ts[SDE_ROTATOR_TS_QUEUE] = ktime_get();
- queue_work(queue->rot_work_queue, &entry->commit_work);
+ queue_kthread_work(&queue->rot_kw, &entry->commit_work);
}
}
@@ -1377,12 +1401,13 @@ static void sde_rotator_release_entry(struct sde_rot_mgr *mgr,
*
* Note this asynchronous handler is protected by hal lock.
*/
-static void sde_rotator_commit_handler(struct work_struct *work)
+static void sde_rotator_commit_handler(struct kthread_work *work)
{
struct sde_rot_entry *entry;
struct sde_rot_entry_container *request;
struct sde_rot_hw_resource *hw;
struct sde_rot_mgr *mgr;
+ struct sched_param param = { .sched_priority = 5 };
int ret;
entry = container_of(work, struct sde_rot_entry, commit_work);
@@ -1393,6 +1418,12 @@ static void sde_rotator_commit_handler(struct work_struct *work)
return;
}
+ ret = sched_setscheduler(entry->fenceq->rot_thread, SCHED_FIFO, &param);
+ if (ret) {
+ SDEROT_WARN("Fail to set kthread priority for fenceq: %d\n",
+ ret);
+ }
+
mgr = entry->private->mgr;
SDEROT_EVTLOG(
@@ -1466,7 +1497,7 @@ static void sde_rotator_commit_handler(struct work_struct *work)
if (entry->item.ts)
entry->item.ts[SDE_ROTATOR_TS_FLUSH] = ktime_get();
- queue_work(entry->doneq->rot_work_queue, &entry->done_work);
+ queue_kthread_work(&entry->doneq->rot_kw, &entry->done_work);
sde_rot_mgr_unlock(mgr);
return;
error:
@@ -1478,8 +1509,8 @@ get_hw_res_err:
sde_rotator_release_entry(mgr, entry);
atomic_dec(&request->pending_count);
atomic_inc(&request->failed_count);
- if (request->retireq && request->retire_work)
- queue_work(request->retireq, request->retire_work);
+ if (request->retire_kw && request->retire_work)
+ queue_kthread_work(request->retire_kw, request->retire_work);
sde_rot_mgr_unlock(mgr);
}
@@ -1493,7 +1524,7 @@ get_hw_res_err:
*
* Note this asynchronous handler is protected by hal lock.
*/
-static void sde_rotator_done_handler(struct work_struct *work)
+static void sde_rotator_done_handler(struct kthread_work *work)
{
struct sde_rot_entry *entry;
struct sde_rot_entry_container *request;
@@ -1551,8 +1582,8 @@ static void sde_rotator_done_handler(struct work_struct *work)
ATRACE_INT("sde_rot_done", 1);
sde_rotator_release_entry(mgr, entry);
atomic_dec(&request->pending_count);
- if (request->retireq && request->retire_work)
- queue_work(request->retireq, request->retire_work);
+ if (request->retire_kw && request->retire_work)
+ queue_kthread_work(request->retire_kw, request->retire_work);
if (entry->item.ts)
entry->item.ts[SDE_ROTATOR_TS_RETIRE] = ktime_get();
sde_rot_mgr_unlock(mgr);
@@ -1918,8 +1949,10 @@ static int sde_rotator_add_request(struct sde_rot_mgr *mgr,
entry->request = req;
- INIT_WORK(&entry->commit_work, sde_rotator_commit_handler);
- INIT_WORK(&entry->done_work, sde_rotator_done_handler);
+ init_kthread_work(&entry->commit_work,
+ sde_rotator_commit_handler);
+ init_kthread_work(&entry->done_work,
+ sde_rotator_done_handler);
SDEROT_DBG("Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%u\n"
"dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->wb_idx,
item->src_rect.x, item->src_rect.y,
@@ -1957,24 +1990,26 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr,
struct sde_rot_entry *entry;
int i;
- /*
- * To avoid signal the rotation entry output fence in the wrong
- * order, all the entries in the same request needs to be canceled
- * first, before signaling the output fence.
- */
- SDEROT_DBG("cancel work start\n");
- sde_rot_mgr_unlock(mgr);
- for (i = req->count - 1; i >= 0; i--) {
- entry = req->entries + i;
- cancel_work_sync(&entry->commit_work);
- cancel_work_sync(&entry->done_work);
- }
- sde_rot_mgr_lock(mgr);
- SDEROT_DBG("cancel work done\n");
- for (i = req->count - 1; i >= 0; i--) {
- entry = req->entries + i;
- sde_rotator_signal_output(entry);
- sde_rotator_release_entry(mgr, entry);
+ if (atomic_read(&req->pending_count)) {
+ /*
+ * To avoid signal the rotation entry output fence in the wrong
+ * order, all the entries in the same request needs to be
+ * canceled first, before signaling the output fence.
+ */
+ SDEROT_DBG("cancel work start\n");
+ sde_rot_mgr_unlock(mgr);
+ for (i = req->count - 1; i >= 0; i--) {
+ entry = req->entries + i;
+ flush_kthread_worker(&entry->commitq->rot_kw);
+ flush_kthread_worker(&entry->doneq->rot_kw);
+ }
+ sde_rot_mgr_lock(mgr);
+ SDEROT_DBG("cancel work done\n");
+ for (i = req->count - 1; i >= 0; i--) {
+ entry = req->entries + i;
+ sde_rotator_signal_output(entry);
+ sde_rotator_release_entry(mgr, entry);
+ }
}
list_del_init(&req->list);
@@ -1999,7 +2034,7 @@ static void sde_rotator_free_completed_request(struct sde_rot_mgr *mgr,
list_for_each_entry_safe(req, req_next, &private->req_list, list) {
if ((atomic_read(&req->pending_count) == 0) &&
- (!req->retire_work && !req->retireq)) {
+ (!req->retire_work && !req->retire_kw)) {
list_del_init(&req->list);
devm_kfree(&mgr->pdev->dev, req);
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 2073c6d9f115..41918dd9b43e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/pm_runtime.h>
+#include <linux/kthread.h>
#include "sde_rotator_base.h"
#include "sde_rotator_util.h"
@@ -184,7 +185,8 @@ struct sde_rot_hw_resource {
};
struct sde_rot_queue {
- struct workqueue_struct *rot_work_queue;
+ struct kthread_worker rot_kw;
+ struct task_struct *rot_thread;
struct sde_rot_timeline *timeline;
struct sde_rot_hw_resource *hw;
};
@@ -195,8 +197,8 @@ struct sde_rot_entry_container {
u32 count;
atomic_t pending_count;
atomic_t failed_count;
- struct workqueue_struct *retireq;
- struct work_struct *retire_work;
+ struct kthread_worker *retire_kw;
+ struct kthread_work *retire_work;
struct sde_rot_entry *entries;
};
@@ -205,8 +207,8 @@ struct sde_rot_file_private;
struct sde_rot_entry {
struct sde_rotation_item item;
- struct work_struct commit_work;
- struct work_struct done_work;
+ struct kthread_work commit_work;
+ struct kthread_work done_work;
struct sde_rot_queue *commitq;
struct sde_rot_queue *fenceq;
struct sde_rot_queue *doneq;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index cfee4efb6f16..4298163e37d5 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -53,8 +53,8 @@
#define SDE_ROTATOR_DEGREE_180 180
#define SDE_ROTATOR_DEGREE_90 90
-static void sde_rotator_submit_handler(struct work_struct *work);
-static void sde_rotator_retire_handler(struct work_struct *work);
+static void sde_rotator_submit_handler(struct kthread_work *work);
+static void sde_rotator_retire_handler(struct kthread_work *work);
#ifdef CONFIG_COMPAT
static long sde_rotator_compat_ioctl32(struct file *file,
unsigned int cmd, unsigned long arg);
@@ -466,8 +466,8 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q)
sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
sde_rot_mgr_unlock(rot_dev->mgr);
mutex_unlock(q->lock);
- cancel_work_sync(&ctx->submit_work);
- cancel_work_sync(&ctx->retire_work);
+ flush_kthread_work(&ctx->submit_work);
+ flush_kthread_work(&ctx->retire_work);
mutex_lock(q->lock);
}
@@ -480,7 +480,7 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q)
struct sde_rotator_vbinfo *vbinfo =
&ctx->vbinfo_cap[i];
- if (vbinfo->fence && vbinfo->fd < 0) {
+ if (vbinfo->fence) {
/* fence is not used */
SDEDEV_DBG(rot_dev->dev,
"put fence s:%d t:%d i:%d\n",
@@ -765,8 +765,6 @@ static ssize_t sde_rotator_ctx_show(struct kobject *kobj,
ctx->format_cap.fmt.pix.sizeimage);
SPRINT("abort_pending=%d\n", ctx->abort_pending);
SPRINT("command_pending=%d\n", atomic_read(&ctx->command_pending));
- SPRINT("submit_work=%d\n", work_busy(&ctx->submit_work));
- SPRINT("retire_work=%d\n", work_busy(&ctx->retire_work));
SPRINT("sequence=%u\n",
sde_rotator_get_timeline_commit_ts(ctx->work_queue.timeline));
SPRINT("timestamp=%u\n",
@@ -923,8 +921,8 @@ static int sde_rotator_open(struct file *file)
ctx->crop_out.width = 640;
ctx->crop_out.height = 480;
init_waitqueue_head(&ctx->wait_queue);
- INIT_WORK(&ctx->submit_work, sde_rotator_submit_handler);
- INIT_WORK(&ctx->retire_work, sde_rotator_retire_handler);
+ init_kthread_work(&ctx->submit_work, sde_rotator_submit_handler);
+ init_kthread_work(&ctx->retire_work, sde_rotator_retire_handler);
v4l2_fh_init(&ctx->fh, video);
file->private_data = &ctx->fh;
@@ -954,14 +952,16 @@ static int sde_rotator_open(struct file *file)
snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id,
ctx->session_id);
- ctx->work_queue.rot_work_queue = alloc_ordered_workqueue("%s",
- WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
- if (!ctx->work_queue.rot_work_queue) {
- SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate workqueue\n");
+ init_kthread_worker(&ctx->work_queue.rot_kw);
+ ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn,
+ &ctx->work_queue.rot_kw, name);
+ if (IS_ERR(ctx->work_queue.rot_thread)) {
+ SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n");
ret = -EPERM;
+ ctx->work_queue.rot_thread = NULL;
goto error_alloc_workqueue;
}
- SDEDEV_DBG(ctx->rot_dev->dev, "work queue name=%s\n", name);
+ SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name);
snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id,
ctx->session_id);
@@ -1010,7 +1010,8 @@ error_ctrl_handler:
error_open_session:
sde_rot_mgr_unlock(rot_dev->mgr);
sde_rotator_destroy_timeline(ctx->work_queue.timeline);
- destroy_workqueue(ctx->work_queue.rot_work_queue);
+ flush_kthread_worker(&ctx->work_queue.rot_kw);
+ kthread_stop(ctx->work_queue.rot_thread);
error_alloc_workqueue:
sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
error_create_sysfs:
@@ -1045,20 +1046,17 @@ static int sde_rotator_release(struct file *file)
v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
mutex_unlock(&rot_dev->lock);
- SDEDEV_DBG(rot_dev->dev, "release submit work s:%d w:%x\n",
- session_id, work_busy(&ctx->submit_work));
- cancel_work_sync(&ctx->submit_work);
+ SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id);
+ flush_kthread_worker(&ctx->work_queue.rot_kw);
SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id);
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_session_close(rot_dev->mgr, ctx->private, session_id);
sde_rot_mgr_unlock(rot_dev->mgr);
- SDEDEV_DBG(rot_dev->dev, "release retire work s:%d w:%x\n",
- session_id, work_busy(&ctx->retire_work));
- cancel_work_sync(&ctx->retire_work);
+ SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n", session_id);
mutex_lock(&rot_dev->lock);
SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id);
sde_rotator_destroy_timeline(ctx->work_queue.timeline);
- destroy_workqueue(ctx->work_queue.rot_work_queue);
+ kthread_stop(ctx->work_queue.rot_thread);
sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
kobject_put(&ctx->kobj);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
@@ -1459,7 +1457,7 @@ static int sde_rotator_dqbuf(struct file *file,
&& (buf->index < ctx->nbuf_cap)) {
int idx = buf->index;
- if (ctx->vbinfo_cap[idx].fence && ctx->vbinfo_cap[idx].fd < 0) {
+ if (ctx->vbinfo_cap[idx].fence) {
/* fence is not used */
SDEDEV_DBG(ctx->rot_dev->dev, "put fence s:%d i:%d\n",
ctx->session_id, idx);
@@ -1856,6 +1854,7 @@ static long sde_rotator_private_ioctl(struct file *file, void *fh,
ctx->session_id);
return vbinfo->fd;
}
+ vbinfo->fence = NULL;
}
fence->fd = vbinfo->fd;
@@ -2023,7 +2022,7 @@ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = {
*
* This function is scheduled in work queue context.
*/
-static void sde_rotator_retire_handler(struct work_struct *work)
+static void sde_rotator_retire_handler(struct kthread_work *work)
{
struct vb2_v4l2_buffer *src_buf;
struct vb2_v4l2_buffer *dst_buf;
@@ -2209,7 +2208,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
goto error_init_request;
}
- req->retireq = ctx->work_queue.rot_work_queue;
+ req->retire_kw = &ctx->work_queue.rot_kw;
req->retire_work = &ctx->retire_work;
ret = sde_rotator_handle_request_common(
@@ -2238,7 +2237,7 @@ error_null_buffer:
*
* This function is scheduled in work queue context.
*/
-static void sde_rotator_submit_handler(struct work_struct *work)
+static void sde_rotator_submit_handler(struct kthread_work *work)
{
struct sde_rotator_ctx *ctx;
struct sde_rotator_device *rot_dev;
@@ -2325,7 +2324,7 @@ static void sde_rotator_device_run(void *priv)
/* disconnect request (will be freed by core layer) */
sde_rot_mgr_lock(rot_dev->mgr);
- ctx->request->retireq = NULL;
+ ctx->request->retire_kw = NULL;
ctx->request->retire_work = NULL;
ctx->request = NULL;
sde_rot_mgr_unlock(rot_dev->mgr);
@@ -2364,7 +2363,7 @@ static void sde_rotator_device_run(void *priv)
/* disconnect request (will be freed by core layer) */
sde_rot_mgr_lock(rot_dev->mgr);
- ctx->request->retireq = NULL;
+ ctx->request->retire_kw = NULL;
ctx->request->retire_work = NULL;
ctx->request = ERR_PTR(-EIO);
sde_rot_mgr_unlock(rot_dev->mgr);
@@ -2471,7 +2470,7 @@ static int sde_rotator_job_ready(void *priv)
v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx),
atomic_read(&ctx->command_pending));
atomic_inc(&ctx->command_pending);
- queue_work(ctx->work_queue.rot_work_queue, &ctx->submit_work);
+ queue_kthread_work(&ctx->work_queue.rot_kw, &ctx->submit_work);
} else if (!atomic_read(&ctx->request->pending_count)) {
/* if pending request completed, forward to device run state */
SDEDEV_DBG(rot_dev->dev,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
index c8dcdeee9ca0..8e4d86083508 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.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
@@ -21,6 +21,7 @@
#include <linux/iommu.h>
#include <linux/dma-buf.h>
#include <linux/msm-bus.h>
+#include <linux/kthread.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
@@ -131,8 +132,8 @@ struct sde_rotator_ctx {
struct sde_rotator_vbinfo *vbinfo_cap;
struct sde_rotator_vbinfo *vbinfo_out;
wait_queue_head_t wait_queue;
- struct work_struct submit_work;
- struct work_struct retire_work;
+ struct kthread_work submit_work;
+ struct kthread_work retire_work;
struct sde_rot_queue work_queue;
struct sde_rot_entry_container *request;
struct sde_rot_file_private *private;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
index 3e269576c126..9bc313adb10a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c
@@ -407,8 +407,10 @@ static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst)
if (dcvs->etb_counter < total_input_buf) {
dcvs->etb_counter++;
- if (dcvs->etb_counter != total_input_buf)
- return rc;
+ if (dcvs->etb_counter != total_input_buf) {
+ return msm_comm_scale_clocks_load(core, dcvs->load,
+ LOAD_CALC_NO_QUIRKS);
+ }
}
dprintk(VIDC_PROF,
@@ -425,7 +427,7 @@ static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst)
}
if (fw_pending_bufs >= DCVS_ENC_HIGH_THR &&
- dcvs->load <= dcvs->load_low) {
+ dcvs->load < dcvs->load_high) {
dcvs->load = dcvs->load_high;
dcvs->prev_freq_increased = true;
} else {
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index 783337d22f36..10a02934bfc0 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -158,11 +158,8 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
/* Do this outside the status_mutex to avoid a circular dependency with
* the locking in cxl_mmap_fault() */
- if (copy_from_user(&work, uwork,
- sizeof(struct cxl_ioctl_start_work))) {
- rc = -EFAULT;
- goto out;
- }
+ if (copy_from_user(&work, uwork, sizeof(work)))
+ return -EFAULT;
mutex_lock(&ctx->status_mutex);
if (ctx->status != OPENED) {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 500185546599..7cdcd69cecf4 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -4379,9 +4379,9 @@ int qseecom_start_app(struct qseecom_handle **handle,
return -EINVAL;
}
- if (strlen(app_name) >= MAX_APP_NAME_SIZE) {
+ if (strnlen(app_name, MAX_APP_NAME_SIZE) == MAX_APP_NAME_SIZE) {
pr_err("The app_name (%s) with length %zu is not valid\n",
- app_name, strlen(app_name));
+ app_name, strnlen(app_name, MAX_APP_NAME_SIZE));
return -EINVAL;
}
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 091370f4ea40..3c9d311106cd 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -94,7 +94,7 @@ static struct uid_entry *find_or_register_uid(uid_t uid)
static int uid_cputime_show(struct seq_file *m, void *v)
{
- struct uid_entry *uid_entry;
+ struct uid_entry *uid_entry = NULL;
struct task_struct *task, *temp;
struct user_namespace *user_ns = current_user_ns();
cputime_t utime;
@@ -112,7 +112,8 @@ static int uid_cputime_show(struct seq_file *m, void *v)
read_lock(&tasklist_lock);
do_each_thread(temp, task) {
uid = from_kuid_munged(user_ns, task_uid(task));
- uid_entry = find_or_register_uid(uid);
+ if (!uid_entry || uid_entry->uid != uid)
+ uid_entry = find_or_register_uid(uid);
if (!uid_entry) {
read_unlock(&tasklist_lock);
rt_mutex_unlock(&uid_lock);
@@ -251,7 +252,7 @@ static void compute_uid_io_bucket_stats(struct io_stats *io_bucket,
static void update_io_stats_all_locked(void)
{
- struct uid_entry *uid_entry;
+ struct uid_entry *uid_entry = NULL;
struct task_struct *task, *temp;
struct user_namespace *user_ns = current_user_ns();
unsigned long bkt;
@@ -264,7 +265,8 @@ static void update_io_stats_all_locked(void)
rcu_read_lock();
do_each_thread(temp, task) {
uid = from_kuid_munged(user_ns, task_uid(task));
- uid_entry = find_or_register_uid(uid);
+ if (!uid_entry || uid_entry->uid != uid)
+ uid_entry = find_or_register_uid(uid);
if (!uid_entry)
continue;
add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index c82ab87fcbe8..e5911ccb2148 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1949,7 +1949,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* select a non-FCoE queue */
- return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
+ return fallback(dev, skb) % (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos);
}
void bnx2x_set_num_queues(struct bnx2x *bp)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 0d147610a06f..090e00650601 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2714,10 +2714,14 @@ static int cxgb_up(struct adapter *adap)
if (err)
goto irq_err;
}
+
+ mutex_lock(&uld_mutex);
enable_rx(adap);
t4_sge_start(adap);
t4_intr_enable(adap);
adap->flags |= FULL_INIT_DONE;
+ mutex_unlock(&uld_mutex);
+
notify_ulds(adap, CXGB4_STATE_UP);
#if IS_ENABLED(CONFIG_IPV6)
update_clip(adap);
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index ff665493ca97..52f2230062e7 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -713,6 +713,8 @@ static int ethoc_open(struct net_device *dev)
if (ret)
return ret;
+ napi_enable(&priv->napi);
+
ethoc_init_ring(priv, dev->mem_start);
ethoc_reset(priv);
@@ -725,7 +727,6 @@ static int ethoc_open(struct net_device *dev)
}
phy_start(priv->phy);
- napi_enable(&priv->napi);
if (netif_msg_ifup(priv)) {
dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n",
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 590750ab6564..9a986ccd42e5 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -77,6 +77,8 @@ static const u8 all_zeros_mac[ETH_ALEN];
static int vxlan_sock_add(struct vxlan_dev *vxlan);
+static void vxlan_vs_del_dev(struct vxlan_dev *vxlan);
+
/* per-network namespace private data for this module */
struct vxlan_net {
struct list_head vxlan_list;
@@ -1052,6 +1054,8 @@ static void __vxlan_sock_release(struct vxlan_sock *vs)
static void vxlan_sock_release(struct vxlan_dev *vxlan)
{
+ vxlan_vs_del_dev(vxlan);
+
__vxlan_sock_release(vxlan->vn4_sock);
#if IS_ENABLED(CONFIG_IPV6)
__vxlan_sock_release(vxlan->vn6_sock);
@@ -2255,6 +2259,15 @@ static void vxlan_cleanup(unsigned long arg)
mod_timer(&vxlan->age_timer, next_timer);
}
+static void vxlan_vs_del_dev(struct vxlan_dev *vxlan)
+{
+ struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
+
+ spin_lock(&vn->sock_lock);
+ hlist_del_init_rcu(&vxlan->hlist);
+ spin_unlock(&vn->sock_lock);
+}
+
static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
@@ -3028,12 +3041,6 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev,
static void vxlan_dellink(struct net_device *dev, struct list_head *head)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
-
- spin_lock(&vn->sock_lock);
- if (!hlist_unhashed(&vxlan->hlist))
- hlist_del_rcu(&vxlan->hlist);
- spin_unlock(&vn->sock_lock);
gro_cells_destroy(&vxlan->gro_cells);
list_del(&vxlan->next);
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 95412139e7f6..6906bddb229f 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1550,6 +1550,7 @@ static void ath10k_core_restart(struct work_struct *work)
complete(&ar->offchan_tx_completed);
complete(&ar->install_key_done);
complete(&ar->vdev_setup_done);
+ complete(&ar->vdev_delete_done);
complete(&ar->thermal.wmi_sync);
complete(&ar->bss_survey_done);
wake_up(&ar->htt.empty_tx_wq);
@@ -2373,6 +2374,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
+ init_completion(&ar->vdev_delete_done);
init_completion(&ar->thermal.wmi_sync);
init_completion(&ar->bss_survey_done);
init_completion(&ar->peer_delete_done);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index fa2e226ec085..8ddbae96794d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -365,7 +365,8 @@ struct ath10k_sta {
#endif
};
-#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
+#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
+#define ATH10K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)
enum ath10k_beacon_state {
ATH10K_BEACON_SCHEDULED = 0,
@@ -853,6 +854,7 @@ struct ath10k {
struct completion install_key_done;
struct completion vdev_setup_done;
+ struct completion vdev_delete_done;
struct workqueue_struct *workqueue;
/* Auxiliary workqueue */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0f0826291ab4..24485466704b 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -994,6 +994,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
@@ -1043,6 +1044,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ar->monitor_vdev_id, ret);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
@@ -1349,6 +1351,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) {
@@ -1385,6 +1388,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
arg.vdev_id = arvif->vdev_id;
arg.dtim_period = arvif->dtim_period;
@@ -5123,6 +5127,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ath10k_peer *peer;
+ unsigned long time_left;
int ret;
int i;
@@ -5162,6 +5167,16 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
arvif->vdev_id, ret);
+ if (QCA_REV_WCN3990(ar)) {
+ time_left = wait_for_completion_timeout(
+ &ar->vdev_delete_done,
+ ATH10K_VDEV_DELETE_TIMEOUT_HZ);
+ if (time_left == 0) {
+ ath10k_warn(ar, "Timeout in receiving vdev delete resp\n");
+ return;
+ }
+ }
+
/* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted.
*/
@@ -5215,6 +5230,26 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&ar->conf_mutex);
}
+static int ath10k_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type, bool p2p)
+{
+ struct ath10k *ar = hw->priv;
+ int ret = 0;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "change_interface new: %d (%d), old: %d (%d)\n", new_type,
+ p2p, vif->type, vif->p2p);
+
+ if (new_type != vif->type || vif->p2p != p2p) {
+ ath10k_remove_interface(hw, vif);
+ vif->type = new_type;
+ vif->p2p = p2p;
+ ret = ath10k_add_interface(hw, vif);
+ }
+ return ret;
+}
+
/*
* FIXME: Has to be verified.
*/
@@ -7456,6 +7491,7 @@ static const struct ieee80211_ops ath10k_ops = {
.stop = ath10k_stop,
.config = ath10k_config,
.add_interface = ath10k_add_interface,
+ .change_interface = ath10k_change_interface,
.remove_interface = ath10k_remove_interface,
.configure_filter = ath10k_configure_filter,
.bss_info_changed = ath10k_bss_info_changed,
@@ -7752,6 +7788,81 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {
},
};
+static const struct ieee80211_iface_limit ath10k_wcn3990_if_limit[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+};
+
+static const struct ieee80211_iface_limit ath10k_wcn3990_qcs_if_limit[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+};
+
+static const struct ieee80211_iface_limit ath10k_wcn3990_if_limit_ibss[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC),
+ },
+};
+
+static struct ieee80211_iface_combination ath10k_wcn3990_qcs_if_comb[] = {
+ {
+ .limits = ath10k_wcn3990_if_limit,
+ .num_different_channels = 1,
+ .max_interfaces = 4,
+ .n_limits = ARRAY_SIZE(ath10k_wcn3990_if_limit),
+ },
+ {
+ .limits = ath10k_wcn3990_qcs_if_limit,
+ .num_different_channels = 2,
+ .max_interfaces = 4,
+ .n_limits = ARRAY_SIZE(ath10k_wcn3990_qcs_if_limit),
+ },
+ {
+ .limits = ath10k_wcn3990_if_limit_ibss,
+ .num_different_channels = 1,
+ .max_interfaces = 2,
+ .n_limits = ARRAY_SIZE(ath10k_wcn3990_if_limit_ibss),
+ },
+};
+
static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = {
{
.max = 1,
@@ -7983,6 +8094,14 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
+ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+ if (QCA_REV_WCN3990(ar)) {
+ ar->hw->wiphy->iface_combinations =
+ ath10k_wcn3990_qcs_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_wcn3990_qcs_if_comb);
+ break;
+ }
if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
ar->hw->wiphy->iface_combinations =
ath10k_tlv_qcs_if_comb;
@@ -7993,7 +8112,6 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_tlv_if_comb);
}
- ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
case ATH10K_FW_WMI_OP_VERSION_10_2:
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 36026a15f721..1544eb175c7f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -477,6 +477,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_VDEV_STOPPED_EVENTID:
ath10k_wmi_event_vdev_stopped(ar, skb);
break;
+ case WMI_TLV_VDEV_DELETE_RESP_EVENTID:
+ ath10k_wmi_event_vdev_delete_resp(ar, skb);
+ break;
case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
ath10k_wmi_event_peer_sta_kickout(ar, skb);
break;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index f8139bcf79cc..86b24c24d9f1 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -308,6 +308,8 @@ enum wmi_tlv_event_id {
WMI_TLV_VDEV_STOPPED_EVENTID,
WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
+ WMI_TLV_VDEV_TSF_REPORT_EVENTID,
+ WMI_TLV_VDEV_DELETE_RESP_EVENTID,
WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
WMI_TLV_PEER_INFO_EVENTID,
WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index cbbba8d79e6b..c36b0fc435d4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3120,6 +3120,12 @@ void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb)
complete(&ar->vdev_setup_done);
}
+void ath10k_wmi_event_vdev_delete_resp(struct ath10k *ar, struct sk_buff *skb)
+{
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_DELETE_RESP_EVENTID\n");
+ complete(&ar->vdev_delete_done);
+}
+
static int
ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
struct wmi_peer_kick_ev_arg *arg)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 74398b45e365..13cac69581d6 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6599,6 +6599,7 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_delete_resp(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb);
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
index 48d358c4722a..22c59d8c3c45 100644
--- a/drivers/net/wireless/cnss/cnss_pci.c
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -134,6 +134,7 @@ static DEFINE_SPINLOCK(pci_link_down_lock);
#define FW_IMAGE_MISSION (0x02)
#define FW_IMAGE_BDATA (0x03)
#define FW_IMAGE_PRINT (0x04)
+#define FW_SETUP_DELAY 2000
#define SEG_METADATA (0x01)
#define SEG_NON_PAGED (0x02)
@@ -244,7 +245,7 @@ static struct cnss_data {
struct pci_saved_state *saved_state;
u16 revision_id;
bool recovery_in_progress;
- bool fw_available;
+ atomic_t fw_available;
struct codeswap_codeseg_info *cnss_seg_info;
/* Virtual Address of the DMA page */
void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS];
@@ -273,6 +274,10 @@ static struct cnss_data {
u32 fw_dma_size;
u32 fw_seg_count;
struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
+ atomic_t fw_store_in_progress;
+ /* Firmware setup complete lock */
+ struct mutex fw_setup_stat_lock;
+ struct completion fw_setup_complete;
void *bdata_cpu;
dma_addr_t bdata_dma;
u32 bdata_dma_size;
@@ -1369,10 +1374,21 @@ int cnss_get_fw_image(struct image_desc_info *image_desc_info)
!penv->fw_seg_count || !penv->bdata_seg_count)
return -EINVAL;
+ /* Check for firmware setup trigger by usersapce is in progress
+ * and wait for complition of firmware setup.
+ */
+
+ if (atomic_read(&penv->fw_store_in_progress)) {
+ wait_for_completion_timeout(&penv->fw_setup_complete,
+ msecs_to_jiffies(FW_SETUP_DELAY));
+ }
+
+ mutex_lock(&penv->fw_setup_stat_lock);
image_desc_info->fw_addr = penv->fw_dma;
image_desc_info->fw_size = penv->fw_dma_size;
image_desc_info->bdata_addr = penv->bdata_dma;
image_desc_info->bdata_size = penv->bdata_dma_size;
+ mutex_unlock(&penv->fw_setup_stat_lock);
return 0;
}
@@ -1552,7 +1568,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,
penv->pdev = pdev;
penv->id = id;
- penv->fw_available = false;
+ atomic_set(&penv->fw_available, 0);
penv->device_id = pdev->device;
if (penv->smmu_iova_len) {
@@ -1858,8 +1874,19 @@ static ssize_t fw_image_setup_store(struct device *dev,
if (!penv)
return -ENODEV;
- if (sscanf(buf, "%d", &val) != 1)
+ if (atomic_read(&penv->fw_store_in_progress)) {
+ pr_info("%s: Firmware setup in progress\n", __func__);
+ return 0;
+ }
+
+ atomic_set(&penv->fw_store_in_progress, 1);
+ init_completion(&penv->fw_setup_complete);
+
+ if (kstrtoint(buf, 0, &val)) {
+ atomic_set(&penv->fw_store_in_progress, 0);
+ complete(&penv->fw_setup_complete);
return -EINVAL;
+ }
if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION
|| val == FW_IMAGE_BDATA) {
@@ -1868,6 +1895,8 @@ static ssize_t fw_image_setup_store(struct device *dev,
if (ret != 0) {
pr_err("%s: Invalid parsing of FW image files %d",
__func__, ret);
+ atomic_set(&penv->fw_store_in_progress, 0);
+ complete(&penv->fw_setup_complete);
return -EINVAL;
}
penv->fw_image_setup = val;
@@ -1877,6 +1906,9 @@ static ssize_t fw_image_setup_store(struct device *dev,
penv->bmi_test = val;
}
+ atomic_set(&penv->fw_store_in_progress, 0);
+ complete(&penv->fw_setup_complete);
+
return count;
}
@@ -1979,7 +2011,7 @@ int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
swap_seg = NULL;
return -ENOENT;
}
- if (!penv->fw_available) {
+ if (!atomic_read(&penv->fw_available)) {
pr_debug("%s: fw is not available\n", __func__);
return -ENOENT;
}
@@ -2003,6 +2035,16 @@ static void cnss_wlan_memory_expansion(void)
u_int32_t total_length = 0;
struct pci_dev *pdev;
+ /* Check for firmware setup trigger by usersapce is in progress
+ * and wait for complition of firmware setup.
+ */
+
+ if (atomic_read(&penv->fw_store_in_progress)) {
+ wait_for_completion_timeout(&penv->fw_setup_complete,
+ msecs_to_jiffies(FW_SETUP_DELAY));
+ }
+
+ mutex_lock(&penv->fw_setup_stat_lock);
filename = cnss_wlan_get_evicted_data_file();
pdev = penv->pdev;
dev = &pdev->dev;
@@ -2010,21 +2052,25 @@ static void cnss_wlan_memory_expansion(void)
if (!cnss_seg_info) {
pr_debug("cnss: cnss_seg_info is NULL\n");
+ mutex_unlock(&penv->fw_setup_stat_lock);
goto end;
}
- if (penv->fw_available) {
+ if (atomic_read(&penv->fw_available)) {
pr_debug("cnss: fw code already copied to host memory\n");
+ mutex_unlock(&penv->fw_setup_stat_lock);
goto end;
}
if (request_firmware(&fw_entry, filename, dev) != 0) {
pr_debug("cnss: failed to get fw: %s\n", filename);
+ mutex_unlock(&penv->fw_setup_stat_lock);
goto end;
}
if (!fw_entry || !fw_entry->data) {
pr_err("%s: INVALID FW entries\n", __func__);
+ mutex_unlock(&penv->fw_setup_stat_lock);
goto release_fw;
}
@@ -2059,7 +2105,9 @@ static void cnss_wlan_memory_expansion(void)
}
pr_debug("cnss: total_bytes copied: %d\n", total_length);
cnss_seg_info->codeseg_total_bytes = total_length;
- penv->fw_available = 1;
+
+ atomic_set(&penv->fw_available, 1);
+ mutex_unlock(&penv->fw_setup_stat_lock);
release_fw:
release_firmware(fw_entry);
@@ -2968,6 +3016,8 @@ skip_ramdump:
memset(phys_to_virt(0), 0, SZ_4K);
#endif
+ atomic_set(&penv->fw_store_in_progress, 0);
+ mutex_init(&penv->fw_setup_stat_lock);
ret = device_create_file(dev, &dev_attr_fw_image_setup);
if (ret) {
pr_err("cnss: fw_image_setup sys file creation failed\n");
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 1f445f357da1..888e9cfef51a 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -304,7 +304,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
queue->rx_skbs[id] = skb;
ref = gnttab_claim_grant_reference(&queue->gref_rx_head);
- BUG_ON((signed short)ref < 0);
+ WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref));
queue->grant_rx_ref[id] = ref;
page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
@@ -437,7 +437,7 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset,
id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++);
ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
- BUG_ON((signed short)ref < 0);
+ WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref));
gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id,
gfn, GNTMAP_readonly);
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 39400dda27c2..63ec68e6ac2a 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -552,7 +552,6 @@ static void armpmu_init(struct arm_pmu *armpmu)
.stop = armpmu_stop,
.read = armpmu_read,
.filter_match = armpmu_filter_match,
- .events_across_hotplug = 1,
};
}
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 08bffc344429..b111a5904952 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1319,6 +1319,35 @@ int gsi_query_evt_ring_db_addr(unsigned long evt_ring_hdl,
}
EXPORT_SYMBOL(gsi_query_evt_ring_db_addr);
+int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value)
+{
+ struct gsi_evt_ctx *ctx;
+
+ if (!gsi_ctx) {
+ pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
+ return -GSI_STATUS_NODEV;
+ }
+
+ if (evt_ring_hdl >= gsi_ctx->max_ev) {
+ GSIERR("bad params evt_ring_hdl=%lu\n", evt_ring_hdl);
+ return -GSI_STATUS_INVALID_PARAMS;
+ }
+
+ ctx = &gsi_ctx->evtr[evt_ring_hdl];
+
+ if (ctx->state != GSI_EVT_RING_STATE_ALLOCATED) {
+ GSIERR("bad state %d\n",
+ gsi_ctx->evtr[evt_ring_hdl].state);
+ return -GSI_STATUS_UNSUPPORTED_OP;
+ }
+
+ ctx->ring.wp_local = value;
+ gsi_ring_evt_doorbell(ctx);
+
+ return GSI_STATUS_SUCCESS;
+}
+EXPORT_SYMBOL(gsi_ring_evt_ring_db);
+
int gsi_reset_evt_ring(unsigned long evt_ring_hdl)
{
uint32_t val;
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
index a02247d3e938..5aa39b699bd6 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1059,6 +1059,7 @@ static void ipa_mhi_gsi_ev_err_cb(struct gsi_evt_err_notify *notify)
IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
}
IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
+ ipa_assert();
}
static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify)
@@ -1090,6 +1091,7 @@ static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify)
IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
}
IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
+ ipa_assert();
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 2214dfe89df3..f2909110d09f 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -857,12 +857,16 @@ int ipa2_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in)
return -EINVAL;
}
+ mutex_lock(&ipa_ctx->lock);
/* check if this table exists */
entry = __ipa_find_rt_tbl(in->ip, in->name);
- if (!entry)
+ if (!entry) {
+ mutex_unlock(&ipa_ctx->lock);
return -EFAULT;
+ }
in->idx = entry->idx;
+ mutex_unlock(&ipa_ctx->lock);
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index e349ade46075..bc6622d4725b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -1668,8 +1668,21 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id,
if (should_force_clear) {
result = ipa3_enable_force_clear(qmi_req_id, false,
source_pipe_bitmask);
- if (result)
- goto exit;
+ if (result) {
+ struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 };
+
+ /*
+ * assuming here modem SSR\shutdown, AP can remove
+ * the delay in this case
+ */
+ IPAERR(
+ "failed to force clear %d, remove delay from SCND reg\n"
+ , result);
+ ep_ctrl_scnd.endp_delay = false;
+ ipahal_write_reg_n_fields(
+ IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
+ &ep_ctrl_scnd);
+ }
}
/* with force clear, wait for emptiness */
for (i = 0; i < IPA_POLL_FOR_EMPTINESS_NUM; i++) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index 9e2ffe70170c..cd027c28e597 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -255,6 +255,24 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,
ep->gsi_evt_ring_hdl = *params->cached_gsi_evt_ring_hdl;
}
+ if (params->ev_ctx_host->wp == params->ev_ctx_host->rbase) {
+ IPA_MHI_ERR("event ring wp is not updated. base=wp=0x%llx\n",
+ params->ev_ctx_host->wp);
+ goto fail_alloc_ch;
+ return res;
+ }
+
+ IPA_MHI_DBG("Ring event db: evt_ring_hdl=%lu host_wp=0x%llx\n",
+ ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp);
+ res = gsi_ring_evt_ring_db(ep->gsi_evt_ring_hdl,
+ params->ev_ctx_host->wp);
+ if (res) {
+ IPA_MHI_ERR("fail to ring evt ring db %d. hdl=%lu wp=0x%llx\n",
+ res, ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp);
+ goto fail_alloc_ch;
+ return res;
+ }
+
memset(&ch_props, 0, sizeof(ch_props));
ch_props.prot = GSI_CHAN_PROT_MHI;
ch_props.dir = IPA_CLIENT_IS_PROD(client) ?
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 7212ba2a165c..6197c9f64ca5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -727,12 +727,15 @@ int ipa3_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in)
return -EINVAL;
}
+ mutex_lock(&ipa3_ctx->lock);
/* check if this table exists */
entry = __ipa3_find_rt_tbl(in->ip, in->name);
- if (!entry)
+ if (!entry) {
+ mutex_unlock(&ipa3_ctx->lock);
return -EFAULT;
-
+ }
in->idx = entry->idx;
+ mutex_unlock(&ipa3_ctx->lock);
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index df5454e4776c..5397b6c39419 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1140,7 +1140,8 @@ send:
memset(&meta, 0, sizeof(meta));
meta.pkt_init_dst_ep_valid = true;
meta.pkt_init_dst_ep_remote = true;
- meta.pkt_init_dst_ep = IPA_CLIENT_Q6_LAN_CONS;
+ meta.pkt_init_dst_ep =
+ ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_CONS);
ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, &meta);
} else {
ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index 53c85773b377..4f7d27db8dee 100644
--- a/drivers/platform/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -221,6 +221,11 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp,
goto end;
}
+ if (state == EXT_DISPLAY_CABLE_CONNECT)
+ ext_disp->current_disp = type;
+ else
+ ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
ret = msm_ext_disp_send_cable_notification(ext_disp, state);
/* positive ret value means audio node was switched */
@@ -287,7 +292,6 @@ static bool msm_ext_disp_validate_connect(struct msm_ext_disp *ext_disp,
if (ext_disp->current_disp != type)
return false;
end:
- ext_disp->current_disp = type;
return true;
}
@@ -369,8 +373,6 @@ static int msm_ext_disp_hpd(struct platform_device *pdev,
msm_ext_disp_process_audio(ext_disp, type, state, flags);
msm_ext_disp_update_audio_ops(ext_disp, type, state, flags);
msm_ext_disp_process_display(ext_disp, type, state, flags);
-
- ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
}
pr_debug("Hpd (%d) for display (%s)\n", state,
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index bd77e55bafc6..0dd6017245fa 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -46,7 +46,7 @@ static ssize_t power_supply_show_property(struct device *dev,
static char *type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB", "USB_DCP",
"USB_CDP", "USB_ACA", "USB_HVDCP", "USB_HVDCP_3", "USB_PD",
- "Wireless", "BMS", "Parallel", "Main", "Wipower",
+ "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "Wipower",
"TYPEC", "TYPEC_UFP", "TYPEC_DFP"
};
static char *status_text[] = {
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index acea4f213484..e17c65c1e4e7 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -47,7 +47,7 @@
#define SCM_EDLOAD_MODE 0X01
#define SCM_DLOAD_CMD 0x10
#define SCM_DLOAD_MINIDUMP 0X20
-
+#define SCM_DLOAD_BOTHDUMPS (SCM_DLOAD_MINIDUMP | SCM_DLOAD_FULLDUMP)
static int restart_mode;
static void *restart_reason;
@@ -488,7 +488,8 @@ static ssize_t show_dload_mode(struct kobject *kobj, struct attribute *attr,
char *buf)
{
return scnprintf(buf, PAGE_SIZE, "DLOAD dump type: %s\n",
- (dload_type == SCM_DLOAD_MINIDUMP) ? "mini" : "full");
+ (dload_type == SCM_DLOAD_BOTHDUMPS) ? "both" :
+ ((dload_type == SCM_DLOAD_MINIDUMP) ? "mini" : "full"));
}
static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr,
@@ -502,8 +503,16 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr,
return -ENODEV;
}
dload_type = SCM_DLOAD_MINIDUMP;
- } else {
- pr_err("Invalid value. Use 'full' or 'mini'\n");
+ } else if (sysfs_streq(buf, "both")) {
+ if (!minidump_enabled) {
+ pr_err("Minidump not enabled, setting fulldump only\n");
+ dload_type = SCM_DLOAD_FULLDUMP;
+ return count;
+ }
+ dload_type = SCM_DLOAD_BOTHDUMPS;
+ } else{
+ pr_err("Invalid Dump setup request..\n");
+ pr_err("Supported dumps:'full', 'mini', or 'both'\n");
return -EINVAL;
}
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index e3c85ab705c4..e03681ec13cc 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -3136,6 +3136,7 @@ static int fg_psy_set_property(struct power_supply *psy,
pval->intval);
return -EINVAL;
}
+ break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
rc = fg_set_constant_chg_voltage(chip, pval->intval);
break;
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 49cd7aa6fdac..0908eea3b186 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -465,6 +465,8 @@ static int smb2_usb_get_prop(struct power_supply *psy,
val->intval = 0;
else
val->intval = 1;
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
+ val->intval = 0;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
val->intval = chg->voltage_min_uv;
@@ -1466,15 +1468,6 @@ static int smb2_configure_typec(struct smb_charger *chg)
return rc;
}
- /* configure power role for dual-role */
- rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- TYPEC_POWER_ROLE_CMD_MASK, 0);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure power role for DRP rc=%d\n", rc);
- return rc;
- }
-
/*
* disable Type-C factory mode and stay in Attached.SRC state when VCONN
* over-current happens
@@ -1852,6 +1845,16 @@ static int smb2_init_hw(struct smb2 *chip)
static int smb2_post_init(struct smb2 *chip)
{
struct smb_charger *chg = &chip->chg;
+ int rc;
+
+ /* configure power role for dual-role */
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_POWER_ROLE_CMD_MASK, 0);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't configure power role for DRP rc=%d\n", rc);
+ return rc;
+ }
rerun_election(chg->usb_irq_enable_votable);
@@ -2419,7 +2422,11 @@ static int smb2_probe(struct platform_device *pdev)
goto cleanup;
}
- smb2_post_init(chip);
+ rc = smb2_post_init(chip);
+ if (rc < 0) {
+ pr_err("Failed in post init rc=%d\n", rc);
+ goto cleanup;
+ }
smb2_create_debugfs(chip);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 22944f122c44..19be40bb4785 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -261,7 +261,7 @@ static const struct apsd_result const smblib_apsd_results[] = {
[FLOAT] = {
.name = "FLOAT",
.bit = FLOAT_CHARGER_BIT,
- .pst = POWER_SUPPLY_TYPE_USB_DCP
+ .pst = POWER_SUPPLY_TYPE_USB_FLOAT
},
[HVDCP2] = {
.name = "HVDCP2",
@@ -3488,6 +3488,7 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
break;
case POWER_SUPPLY_TYPE_USB_DCP:
+ case POWER_SUPPLY_TYPE_USB_FLOAT:
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
break;
case POWER_SUPPLY_TYPE_USB_HVDCP:
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3588a56aabb4..5cbf20ab94aa 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2311,10 +2311,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (mem_only) {
if (pci_enable_device_mem(pdev))
- goto probe_out;
+ return ret;
} else {
if (pci_enable_device(pdev))
- goto probe_out;
+ return ret;
}
/* This may fail but that's ok */
@@ -2324,7 +2324,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (!ha) {
ql_log_pci(ql_log_fatal, pdev, 0x0009,
"Unable to allocate memory for ha.\n");
- goto probe_out;
+ goto disable_device;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
"Memory allocated for ha=%p.\n", ha);
@@ -2923,7 +2923,7 @@ iospace_config_failed:
kfree(ha);
ha = NULL;
-probe_out:
+disable_device:
pci_disable_device(pdev);
return ret;
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 544a71e7c242..a2f2cc0c2c51 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -653,7 +653,7 @@ static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba,
unsigned int tag, const char *str)
{
struct ufshcd_lrb *lrbp;
- char *cmd_type;
+ char *cmd_type = NULL;
u8 opcode = 0;
u8 cmd_id = 0, idn = 0;
sector_t lba = -1;
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index ee0fe1622645..f4ffc7df1e9c 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -2884,7 +2884,7 @@ static int glink_tx_common(void *handle, void *pkt_priv,
struct channel_ctx *ctx = (struct channel_ctx *)handle;
uint32_t riid;
int ret = 0;
- struct glink_core_tx_pkt *tx_info;
+ struct glink_core_tx_pkt *tx_info = NULL;
size_t intent_size;
bool is_atomic =
tx_flags & (GLINK_TX_SINGLE_THREADED | GLINK_TX_ATOMIC);
@@ -2899,6 +2899,13 @@ static int glink_tx_common(void *handle, void *pkt_priv,
return ret;
rwref_read_get_atomic(&ctx->ch_state_lhb2, is_atomic);
+ tx_info = kzalloc(sizeof(struct glink_core_tx_pkt),
+ is_atomic ? GFP_ATOMIC : GFP_KERNEL);
+ if (!tx_info) {
+ GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__);
+ ret = -ENOMEM;
+ goto glink_tx_common_err;
+ }
if (!(vbuf_provider || pbuf_provider)) {
ret = -EINVAL;
goto glink_tx_common_err;
@@ -3018,14 +3025,7 @@ static int glink_tx_common(void *handle, void *pkt_priv,
GLINK_INFO_PERF_CH(ctx, "%s: R[%u]:%zu data[%p], size[%zu]. TID %u\n",
__func__, riid, intent_size,
data ? data : iovec, size, current->pid);
- tx_info = kzalloc(sizeof(struct glink_core_tx_pkt),
- is_atomic ? GFP_ATOMIC : GFP_KERNEL);
- if (!tx_info) {
- GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__);
- ch_push_remote_rx_intent(ctx, intent_size, riid, cookie);
- ret = -ENOMEM;
- goto glink_tx_common_err;
- }
+
rwref_lock_init(&tx_info->pkt_ref, glink_tx_pkt_release);
INIT_LIST_HEAD(&tx_info->list_done);
INIT_LIST_HEAD(&tx_info->list_node);
@@ -3050,10 +3050,15 @@ static int glink_tx_common(void *handle, void *pkt_priv,
else
xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info);
+ rwref_read_put(&ctx->ch_state_lhb2);
+ glink_put_ch_ctx(ctx, false);
+ return ret;
+
glink_tx_common_err:
rwref_read_put(&ctx->ch_state_lhb2);
glink_tx_common_err_2:
glink_put_ch_ctx(ctx, false);
+ kfree(tx_info);
return ret;
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 99caa1c84dce..37193bbb23b7 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -2402,7 +2402,7 @@ static int glink_smem_native_probe(struct platform_device *pdev)
einfo->tx_fifo = smem_alloc(SMEM_GLINK_NATIVE_XPRT_FIFO_0,
einfo->tx_fifo_size,
einfo->remote_proc_id,
- SMEM_ITEM_CACHED_FLAG);
+ 0);
if (!einfo->tx_fifo) {
pr_err("%s: smem alloc of tx fifo failed\n", __func__);
rc = -ENOMEM;
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 9690d3c64560..21be894414bc 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -268,6 +268,7 @@ enum icnss_driver_state {
ICNSS_WLFW_EXISTS,
ICNSS_WDOG_BITE,
ICNSS_SHUTDOWN_DONE,
+ ICNSS_HOST_TRIGGERED_PDR,
};
struct ce_irq_list {
@@ -320,6 +321,13 @@ struct icnss_stats {
uint32_t disable;
} ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
+ struct {
+ uint32_t pdr_fw_crash;
+ uint32_t pdr_host_error;
+ uint32_t root_pd_crash;
+ uint32_t root_pd_shutdown;
+ } recovery;
+
uint32_t pm_suspend;
uint32_t pm_suspend_err;
uint32_t pm_resume;
@@ -360,7 +368,6 @@ struct icnss_stats {
uint32_t rejuvenate_ack_req;
uint32_t rejuvenate_ack_resp;
uint32_t rejuvenate_ack_err;
- uint32_t trigger_recovery;
};
#define MAX_NO_OF_MAC_ADDR 4
@@ -369,6 +376,20 @@ struct icnss_wlan_mac_addr {
uint32_t no_of_mac_addr_set;
};
+enum icnss_pdr_cause_index {
+ ICNSS_FW_CRASH,
+ ICNSS_ROOT_PD_CRASH,
+ ICNSS_ROOT_PD_SHUTDOWN,
+ ICNSS_HOST_ERROR,
+};
+
+static const char * const icnss_pdr_cause[] = {
+ [ICNSS_FW_CRASH] = "FW crash",
+ [ICNSS_ROOT_PD_CRASH] = "Root PD crashed",
+ [ICNSS_ROOT_PD_SHUTDOWN] = "Root PD shutdown",
+ [ICNSS_HOST_ERROR] = "Host error",
+};
+
struct service_notifier_context {
void *handle;
uint32_t instance_id;
@@ -2400,6 +2421,11 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
+ if (notif->crashed)
+ priv->stats.recovery.root_pd_crash++;
+ else
+ priv->stats.recovery.root_pd_shutdown++;
+
icnss_ignore_qmi_timeout(true);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
@@ -2479,6 +2505,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
enum pd_subsys_state *state = data;
struct icnss_event_pd_service_down_data *event_data;
struct icnss_uevent_fw_down_data fw_down_data;
+ enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH;
icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
notification, priv->state);
@@ -2493,26 +2520,40 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
if (state == NULL) {
event_data->crashed = true;
+ priv->stats.recovery.root_pd_crash++;
goto event_post;
}
- icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n",
- *state, priv->state);
-
switch (*state) {
case ROOT_PD_WDOG_BITE:
event_data->crashed = true;
event_data->wdog_bite = true;
+ priv->stats.recovery.root_pd_crash++;
break;
case ROOT_PD_SHUTDOWN:
+ cause = ICNSS_ROOT_PD_SHUTDOWN;
+ priv->stats.recovery.root_pd_shutdown++;
+ break;
+ case USER_PD_STATE_CHANGE:
+ if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) {
+ cause = ICNSS_HOST_ERROR;
+ priv->stats.recovery.pdr_host_error++;
+ } else {
+ cause = ICNSS_FW_CRASH;
+ priv->stats.recovery.pdr_fw_crash++;
+ }
break;
default:
event_data->crashed = true;
+ priv->stats.recovery.root_pd_crash++;
break;
}
+ icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n",
+ *state, priv->state, icnss_pdr_cause[cause]);
event_post:
icnss_ignore_qmi_timeout(true);
+ clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
fw_down_data.crashed = event_data->crashed;
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
@@ -3255,7 +3296,6 @@ int icnss_trigger_recovery(struct device *dev)
WARN_ON(1);
icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n",
priv->state);
- priv->stats.trigger_recovery++;
/*
* Initiate PDR, required only for the first instance
@@ -3263,6 +3303,9 @@ int icnss_trigger_recovery(struct device *dev)
ret = service_notif_pd_restart(priv->service_notifier[0].name,
priv->service_notifier[0].instance_id);
+ if (!ret)
+ set_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
+
out:
return ret;
}
@@ -3617,9 +3660,6 @@ static ssize_t icnss_fw_debug_write(struct file *fp,
if (ret)
return ret;
- if (ret == 0)
- memset(&priv->stats, 0, sizeof(priv->stats));
-
return count;
}
@@ -3713,6 +3753,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_SHUTDOWN_DONE:
seq_puts(s, "SHUTDOWN DONE");
continue;
+ case ICNSS_HOST_TRIGGERED_PDR:
+ seq_puts(s, "HOST TRIGGERED PDR");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -3811,7 +3854,10 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
- ICNSS_STATS_DUMP(s, priv, trigger_recovery);
+ ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash);
+ ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error);
+ ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash);
+ ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown);
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
ICNSS_STATS_DUMP(s, priv, pm_suspend);
diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c
index a92e5c416678..0a80016f1942 100644
--- a/drivers/soc/qcom/msm_glink_pkt.c
+++ b/drivers/soc/qcom/msm_glink_pkt.c
@@ -33,7 +33,8 @@
#include <linux/termios.h>
#include <soc/qcom/glink.h>
-
+/* This Limit ensures that auto queue will not exhaust memory on remote side */
+#define MAX_PENDING_GLINK_PKT 5
#define MODULE_NAME "msm_glinkpkt"
#define DEVICE_NAME "glinkpkt"
#define WAKEUPSOURCE_TIMEOUT (2000) /* two seconds */
@@ -136,6 +137,7 @@ struct glink_pkt_dev {
struct glink_link_info link_info;
void *link_state_handle;
bool link_up;
+ bool auto_intent_enabled;
};
/**
@@ -447,8 +449,26 @@ void glink_pkt_notify_state(void *handle, const void *priv, unsigned event)
bool glink_pkt_rmt_rx_intent_req_cb(void *handle, const void *priv, size_t sz)
{
struct queue_rx_intent_work *work_item;
+ int pending_pkt_count = 0;
+ struct glink_rx_pkt *pkt = NULL;
+ unsigned long flags;
+ struct glink_pkt_dev *devp = (struct glink_pkt_dev *)priv;
+
GLINK_PKT_INFO("%s(): QUEUE RX INTENT to receive size[%zu]\n",
__func__, sz);
+ if (devp->auto_intent_enabled) {
+ spin_lock_irqsave(&devp->pkt_list_lock, flags);
+ list_for_each_entry(pkt, &devp->pkt_list, list)
+ pending_pkt_count++;
+ spin_unlock_irqrestore(&devp->pkt_list_lock, flags);
+ if (pending_pkt_count > MAX_PENDING_GLINK_PKT) {
+ GLINK_PKT_ERR("%s failed, max limit reached\n",
+ __func__);
+ return false;
+ }
+ } else {
+ return false;
+ }
work_item = kzalloc(sizeof(*work_item), GFP_ATOMIC);
if (!work_item) {
@@ -457,7 +477,7 @@ bool glink_pkt_rmt_rx_intent_req_cb(void *handle, const void *priv, size_t sz)
}
work_item->intent_size = sz;
- work_item->devp = (struct glink_pkt_dev *)priv;
+ work_item->devp = devp;
INIT_WORK(&work_item->work, glink_pkt_queue_rx_intent_worker);
queue_work(glink_pkt_wq, &work_item->work);
@@ -626,10 +646,11 @@ ssize_t glink_pkt_read(struct file *file,
}
mutex_lock(&devp->ch_lock);
- if (!glink_rx_intent_exists(devp->handle, count)) {
+ if (!glink_pkt_read_avail(devp) &&
+ !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",
+ GLINK_PKT_ERR("%s: failed to queue intent ret[%d]\n",
__func__, ret);
mutex_unlock(&devp->ch_lock);
return ret;
@@ -915,6 +936,7 @@ static long glink_pkt_ioctl(struct file *file, unsigned int cmd,
case GLINK_PKT_IOCTL_QUEUE_RX_INTENT:
ret = get_user(size, (uint32_t *)arg);
GLINK_PKT_INFO("%s: intent size[%d]\n", __func__, size);
+ devp->auto_intent_enabled = false;
ret = glink_queue_rx_intent(devp->handle, devp, size);
if (ret) {
GLINK_PKT_ERR("%s: failed to QUEUE_RX_INTENT ret[%d]\n",
@@ -1183,6 +1205,7 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i)
glink_pkt_link_state_cb;
devp->i = i;
devp->poll_mode = 0;
+ devp->auto_intent_enabled = true;
devp->ws_locked = 0;
devp->ch_state = GLINK_LOCAL_DISCONNECTED;
/* Default timeout for open wait is 120sec */
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 36804b988d62..31de6e5c173c 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -731,10 +731,6 @@ int scm_call2_atomic(u32 fn_id, struct scm_desc *desc)
x0 = fn_id | BIT(SMC_ATOMIC_SYSCALL) | scm_version_mask;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
if (scm_version == SCM_ARMV8_64)
ret = __scm_call_armv8_64(x0, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2],
@@ -746,9 +742,8 @@ int scm_call2_atomic(u32 fn_id, struct scm_desc *desc)
desc->x5, &desc->ret[0],
&desc->ret[1], &desc->ret[2]);
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0],
desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c
index 34b46d25a823..2ef25e48ce50 100644
--- a/drivers/soc/qcom/smp2p_sleepstate.c
+++ b/drivers/soc/qcom/smp2p_sleepstate.c
@@ -14,6 +14,8 @@
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
+#include <linux/delay.h>
+#include <linux/ipc_router.h>
#include "smp2p_private.h"
#define SET_DELAY (2 * HZ)
@@ -35,10 +37,14 @@ static int sleepstate_pm_notifier(struct notifier_block *nb,
switch (event) {
case PM_SUSPEND_PREPARE:
gpio_set_value(slst_gpio_base_id + PROC_AWAKE_ID, 0);
+ msleep(25); /* To be tuned based on SMP2P latencies */
+ msm_ipc_router_set_ws_allowed(true);
break;
case PM_POST_SUSPEND:
gpio_set_value(slst_gpio_base_id + PROC_AWAKE_ID, 1);
+ msleep(25); /* To be tuned based on SMP2P latencies */
+ msm_ipc_router_set_ws_allowed(false);
break;
}
return NOTIFY_DONE;
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 3c9d8efd3956..5fe3c572628b 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -58,6 +58,7 @@ struct wdsp_glink_rsp_que {
struct wdsp_glink_tx_buf {
struct work_struct tx_work;
+ struct work_struct free_tx_work;
/* Glink channel information */
struct wdsp_glink_ch *ch;
@@ -125,6 +126,46 @@ static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch);
static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch);
/*
+ * wdsp_glink_free_tx_buf_work - Work function to free tx pkt
+ * work: Work structure
+ */
+static void wdsp_glink_free_tx_buf_work(struct work_struct *work)
+{
+ struct wdsp_glink_tx_buf *tx_buf;
+
+ tx_buf = container_of(work, struct wdsp_glink_tx_buf,
+ free_tx_work);
+ vfree(tx_buf);
+}
+
+/*
+ * wdsp_glink_free_tx_buf - Function to free tx buffer
+ * priv: Pointer to the channel
+ * pkt_priv: Pointer to the tx buffer
+ */
+static void wdsp_glink_free_tx_buf(const void *priv, const void *pkt_priv)
+{
+ struct wdsp_glink_tx_buf *tx_buf = (struct wdsp_glink_tx_buf *)pkt_priv;
+ struct wdsp_glink_priv *wpriv;
+ struct wdsp_glink_ch *ch;
+
+ if (!priv) {
+ pr_err("%s: Invalid priv\n", __func__);
+ return;
+ }
+ if (!tx_buf) {
+ pr_err("%s: Invalid tx_buf\n", __func__);
+ return;
+ }
+
+ ch = (struct wdsp_glink_ch *)priv;
+ wpriv = ch->wpriv;
+ /* Work queue to free tx pkt */
+ INIT_WORK(&tx_buf->free_tx_work, wdsp_glink_free_tx_buf_work);
+ queue_work(wpriv->work_queue, &tx_buf->free_tx_work);
+}
+
+/*
* wdsp_glink_notify_rx - Glink notify rx callback for responses
* handle: Opaque Channel handle returned by GLink
* priv: Private pointer to the channel
@@ -183,14 +224,8 @@ static void wdsp_glink_notify_rx(void *handle, const void *priv,
static void wdsp_glink_notify_tx_done(void *handle, const void *priv,
const void *pkt_priv, const void *ptr)
{
- if (!pkt_priv) {
- pr_err("%s: Invalid parameter\n", __func__);
- return;
- }
- /* Free tx pkt */
- vfree(pkt_priv);
+ wdsp_glink_free_tx_buf(priv, pkt_priv);
}
-
/*
* wdsp_glink_notify_tx_abort - Glink notify tx abort callback to
* free tx buffer
@@ -201,12 +236,7 @@ static void wdsp_glink_notify_tx_done(void *handle, const void *priv,
static void wdsp_glink_notify_tx_abort(void *handle, const void *priv,
const void *pkt_priv)
{
- if (!pkt_priv) {
- pr_err("%s: Invalid parameter\n", __func__);
- return;
- }
- /* Free tx pkt */
- vfree(pkt_priv);
+ wdsp_glink_free_tx_buf(priv, pkt_priv);
}
/*
@@ -555,7 +585,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
goto done;
}
ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!ch) {
ret = -ENOMEM;
goto done;
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index 2fb1e974cc70..e11b1001d1f6 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -399,18 +399,10 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm,
struct lov_mds_md *lmmk = NULL;
int rc, lmm_size;
int lum_size;
- mm_segment_t seg;
if (!lsm)
return -ENODATA;
- /*
- * "Switch to kernel segment" to allow copying from kernel space by
- * copy_{to,from}_user().
- */
- seg = get_fs();
- set_fs(KERNEL_DS);
-
/* we only need the header part from user space to get lmm_magic and
* lmm_stripe_count, (the header part is common to v1 and v3) */
lum_size = sizeof(struct lov_user_md_v1);
@@ -485,6 +477,5 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm,
obd_free_diskmd(exp, &lmmk);
out_set:
- set_fs(seg);
return rc;
}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index af301414a9f3..60743bf27f37 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1154,15 +1154,28 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
if (cmd->unknown_data_length) {
cmd->data_length = size;
} else if (size != cmd->data_length) {
- pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
+ pr_warn_ratelimited("TARGET_CORE[%s]: Expected Transfer Length:"
" %u does not match SCSI CDB Length: %u for SAM Opcode:"
" 0x%02x\n", cmd->se_tfo->get_fabric_name(),
cmd->data_length, size, cmd->t_task_cdb[0]);
- if (cmd->data_direction == DMA_TO_DEVICE &&
- cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
- pr_err("Rejecting underflow/overflow WRITE data\n");
- return TCM_INVALID_CDB_FIELD;
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
+ pr_err_ratelimited("Rejecting underflow/overflow"
+ " for WRITE data CDB\n");
+ return TCM_INVALID_CDB_FIELD;
+ }
+ /*
+ * Some fabric drivers like iscsi-target still expect to
+ * always reject overflow writes. Reject this case until
+ * full fabric driver level support for overflow writes
+ * is introduced tree-wide.
+ */
+ if (size > cmd->data_length) {
+ pr_err_ratelimited("Rejecting overflow for"
+ " WRITE control CDB\n");
+ return TCM_INVALID_CDB_FIELD;
+ }
}
/*
* Reject READ_* or WRITE_* with overflow/underflow for
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index c78406cb3325..2df1bf69e7c9 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -3292,40 +3292,55 @@ static int qpnp_adc_tm_remove(struct platform_device *pdev)
static void qpnp_adc_tm_shutdown(struct platform_device *pdev)
{
struct qpnp_adc_tm_chip *chip = dev_get_drvdata(&pdev->dev);
- int rc = 0;
+ int rc = 0, i = 0;
u8 reg_val = 0, status1 = 0, en_ctl1 = 0;
- /* Set measurement in single measurement mode */
- reg_val = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
- rc = qpnp_adc_tm_mode_select(chip, reg_val);
- if (rc < 0)
- pr_err("adc-tm single mode select failed\n");
+ if (!chip->adc_tm_hc) {
+ /* Set measurement in single measurement mode */
+ reg_val = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, reg_val);
+ if (rc < 0)
+ pr_err("adc-tm single mode select failed\n");
+ }
/* Disable bank */
rc = qpnp_adc_tm_disable(chip);
if (rc < 0)
pr_err("adc-tm disable failed\n");
- /* Check if a conversion is in progress */
- rc = qpnp_adc_tm_req_sts_check(chip);
- if (rc < 0)
- pr_err("adc-tm req_sts check failed\n");
+ if (chip->adc_tm_hc) {
+ for (i = 0; i < 8; i++) {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(i),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0)
+ pr_err("multi meas disable failed\n");
+ }
+ } else {
+ /* Check if a conversion is in progress */
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc < 0)
+ pr_err("adc-tm req_sts check failed\n");
- /* Disable multimeasurement */
- reg_val = 0;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN, reg_val, 1);
- if (rc < 0)
- pr_err("adc-tm multi-measurement mode disable failed\n");
+ /* Disable multimeasurement */
+ reg_val = 0;
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN, reg_val, 1);
+ if (rc < 0)
+ pr_err("adc-tm multi-meas mode disable failed\n");
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
- if (rc < 0)
- pr_err("adc-tm status1 read failed\n");
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_ADC_TM_STATUS1, &status1, 1);
+ if (rc < 0)
+ pr_err("adc-tm status1 read failed\n");
- rc = qpnp_adc_tm_read_reg(chip, QPNP_EN_CTL1, &en_ctl1, 1);
- if (rc < 0)
- pr_err("adc-tm en_ctl1 read failed\n");
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_EN_CTL1, &en_ctl1, 1);
+ if (rc < 0)
+ pr_err("adc-tm en_ctl1 read failed\n");
- pr_debug("adc-tm status1=0%x, en_ctl1=0x%x\n", status1, en_ctl1);
+ pr_debug("status1=0%x, en_ctl1=0x%x\n", status1, en_ctl1);
+ }
}
static int qpnp_adc_tm_suspend_noirq(struct device *dev)
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 88246f7e435a..0f23dda60011 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1378,9 +1378,9 @@ static struct spi_driver ifx_spi_driver = {
static void __exit ifx_spi_exit(void)
{
/* unregister */
+ spi_unregister_driver(&ifx_spi_driver);
tty_unregister_driver(tty_drv);
put_tty_driver(tty_drv);
- spi_unregister_driver(&ifx_spi_driver);
unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 63a06ab6ba03..235e150d7b81 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1800,11 +1800,13 @@ static int sci_startup(struct uart_port *port)
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ sci_request_dma(port);
+
ret = sci_request_irq(s);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ sci_free_dma(port);
return ret;
-
- sci_request_dma(port);
+ }
spin_lock_irqsave(&port->lock, flags);
sci_start_tx(port);
@@ -1834,8 +1836,8 @@ static void sci_shutdown(struct uart_port *port)
}
#endif
- sci_free_dma(port);
sci_free_irq(s);
+ sci_free_dma(port);
}
static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 7cef54334b12..1bb629ab8ecc 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2070,13 +2070,12 @@ retry_open:
if (tty) {
mutex_unlock(&tty_mutex);
retval = tty_lock_interruptible(tty);
+ tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */
if (retval) {
if (retval == -EINTR)
retval = -ERESTARTSYS;
goto err_unref;
}
- /* safe to drop the kref from tty_driver_lookup_tty() */
- tty_kref_put(tty);
retval = tty_reopen(tty);
if (retval < 0) {
tty_unlock(tty);
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index d09293bc0e04..cff304abb619 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -24,10 +24,15 @@ EXPORT_SYMBOL(tty_lock);
int tty_lock_interruptible(struct tty_struct *tty)
{
+ int ret;
+
if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
return -EIO;
tty_kref_get(tty);
- return mutex_lock_interruptible(&tty->legacy_mutex);
+ ret = mutex_lock_interruptible(&tty->legacy_mutex);
+ if (ret)
+ tty_kref_put(tty);
+ return ret;
}
void __lockfunc tty_unlock(struct tty_struct *tty)
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 58c8485a0715..923379972707 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -295,7 +295,8 @@ static int ci_role_show(struct seq_file *s, void *data)
{
struct ci_hdrc *ci = s->private;
- seq_printf(s, "%s\n", ci_role(ci)->name);
+ if (ci->role != CI_ROLE_END)
+ seq_printf(s, "%s\n", ci_role(ci)->name);
return 0;
}
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index d8a045fc1fdb..aff086ca97e4 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1982,6 +1982,7 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
+ int ret;
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
return -ENXIO;
@@ -1994,7 +1995,10 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
rdrv->stop = udc_id_switch_for_host;
rdrv->irq = udc_irq;
rdrv->name = "gadget";
- ci->roles[CI_ROLE_GADGET] = rdrv;
- return udc_start(ci);
+ ret = udc_start(ci);
+ if (!ret)
+ ci->roles[CI_ROLE_GADGET] = rdrv;
+
+ return ret;
}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 325cbc9c35d8..b1298f093f13 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -949,6 +949,14 @@ int usb_get_bos_descriptor(struct usb_device *dev)
dev->bos->ss_id =
(struct usb_ss_container_id_descriptor *)buffer;
break;
+ case USB_CAP_TYPE_CONFIG_SUMMARY:
+ /* one such desc per configuration */
+ if (!dev->bos->num_config_summary_desc)
+ dev->bos->config_summary =
+ (struct usb_config_summary_descriptor *)buffer;
+
+ dev->bos->num_config_summary_desc++;
+ break;
default:
break;
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 358ca8dd784f..72d1109f13eb 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -19,6 +19,8 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v3.h>
#include "usb.h"
static inline const char *plural(int n)
@@ -40,6 +42,36 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
+static int usb_audio_max_rev_config(struct usb_host_bos *bos)
+{
+ int desc_cnt, func_cnt, numfunc;
+ int num_cfg_desc;
+ struct usb_config_summary_descriptor *conf_summary;
+
+ if (!bos || !bos->config_summary)
+ goto done;
+
+ conf_summary = bos->config_summary;
+ num_cfg_desc = bos->num_config_summary_desc;
+
+ for (desc_cnt = 0; desc_cnt < num_cfg_desc; desc_cnt++) {
+ numfunc = conf_summary->bNumFunctions;
+ for (func_cnt = 0; func_cnt < numfunc; func_cnt++) {
+ /* look for BADD 3.0 */
+ if (conf_summary->cs_info[func_cnt].bClass ==
+ USB_CLASS_AUDIO &&
+ conf_summary->cs_info[func_cnt].bProtocol ==
+ UAC_VERSION_3 &&
+ conf_summary->cs_info[func_cnt].bSubClass !=
+ FULL_ADC_PROFILE)
+ return conf_summary->bConfigurationValue;
+ }
+ }
+
+done:
+ return -EINVAL;
+}
+
int usb_choose_configuration(struct usb_device *udev)
{
int i;
@@ -130,7 +162,6 @@ int usb_choose_configuration(struct usb_device *udev)
best = c;
break;
}
-
/* If all the remaining configs are vendor-specific,
* choose the first one. */
else if (!best)
@@ -143,7 +174,10 @@ int usb_choose_configuration(struct usb_device *udev)
insufficient_power, plural(insufficient_power));
if (best) {
- i = best->desc.bConfigurationValue;
+ /* choose usb audio class preferred config if available */
+ i = usb_audio_max_rev_config(udev->bos);
+ if (i < 0)
+ i = best->desc.bConfigurationValue;
dev_dbg(&udev->dev,
"configuration #%d chosen from %d choice%s\n",
i, num_configs, plural(num_configs));
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 59d6ac67d072..9b7274821d0b 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -399,7 +399,11 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Caller must hold fsg->lock */
static void wakeup_thread(struct fsg_common *common)
{
- smp_wmb(); /* ensure the write of bh->state is complete */
+ /*
+ * Ensure the reading of thread_wakeup_needed
+ * and the writing of bh->state are completed
+ */
+ smp_mb();
/* Tell the main thread that something has happened */
common->thread_wakeup_needed = 1;
if (common->thread_task)
@@ -649,7 +653,12 @@ static int sleep_thread(struct fsg_common *common, bool can_freeze)
}
__set_current_state(TASK_RUNNING);
common->thread_wakeup_needed = 0;
- smp_rmb(); /* ensure the latest bh->state is visible */
+
+ /*
+ * Ensure the writing of thread_wakeup_needed
+ * and the reading of bh->state are completed
+ */
+ smp_mb();
return rc;
}
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 7d4578b08244..c8afb3a244c3 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1674,6 +1674,8 @@ exit:
int mdss_dp_on(struct mdss_panel_data *pdata)
{
struct mdss_dp_drv_pdata *dp_drv = NULL;
+ bool hpd;
+ int rc = 0;
if (!pdata) {
pr_err("Invalid input data\n");
@@ -1683,6 +1685,22 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
panel_data);
+ mutex_lock(&dp_drv->attention_lock);
+ hpd = dp_drv->cable_connected;
+ mutex_unlock(&dp_drv->attention_lock);
+
+ /* In case of device coming out of PM_SUSPEND, there can be
+ * a corner case where the sink is turned off or the DP cable
+ * is disconnected almost at the same time as userspace triggering
+ * unblank. This can cause the UNBLANK call to be still triggered
+ * before the disconnect event is notified to the userspace.
+ * Avoid turning ON DP path in such cases.
+ */
+ if (!hpd || !dp_drv->alt_mode.dp_status.hpd_high) {
+ pr_err("DP sink not connected\n");
+ return -EINVAL;
+ }
+
/*
* If the link already active, then nothing needs to be done here.
* However, it is possible that the the power_on flag could be
@@ -1707,8 +1725,11 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
* init/deinit during unrelated resume/suspend events,
* add host initialization call before DP power-on.
*/
- if (!dp_drv->dp_initialized)
- mdss_dp_host_init(pdata);
+ if (!dp_drv->dp_initialized) {
+ rc = mdss_dp_host_init(pdata);
+ if (rc < 0)
+ return rc;
+ }
return mdss_dp_on_hpd(dp_drv);
}
@@ -1941,6 +1962,11 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
}
dp_drv->orientation = usbpd_get_plug_orientation(dp_drv->pd);
+ if (dp_drv->orientation == ORIENTATION_NONE) {
+ pr_err("DP cable might be disconnected\n");
+ ret = -EINVAL;
+ goto orientation_error;
+ }
dp_drv->aux_sel_gpio_output = 0;
if (dp_drv->orientation == ORIENTATION_CC2)
@@ -1981,8 +2007,9 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
return 0;
clk_error:
- mdss_dp_regulator_ctrl(dp_drv, false);
mdss_dp_config_gpios(dp_drv, false);
+orientation_error:
+ mdss_dp_regulator_ctrl(dp_drv, false);
vreg_error:
return ret;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
index 7cc94447efdc..d412a1c66e79 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -150,7 +150,7 @@ static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
- int rc, ret;
+ int ret;
/*
* iommu dynamic attach for following conditions.
@@ -167,26 +167,41 @@ static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd)
return -EPERM;
}
- rc = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE,
+ /*
+ * Putting handoff pending to false to ensure smmu attach happens
+ * with early flag attribute
+ */
+ mdata->handoff_pending = false;
+
+ ret = mdss_smmu_set_attribute(MDSS_IOMMU_DOMAIN_UNSECURE, EARLY_MAP, 1);
+ if (ret) {
+ pr_debug("mdss set attribute failed for early map\n");
+ goto end;
+ }
+
+ ret = mdss_iommu_ctrl(1);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("mdss iommu attach failed\n");
+ goto end;
+ }
+
+ ret = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE,
mdp5_data->splash_mem_addr,
mdp5_data->splash_mem_addr,
mdp5_data->splash_mem_size,
IOMMU_READ | IOMMU_NOEXEC);
- if (rc) {
- pr_debug("iommu memory mapping failed rc=%d\n", rc);
+ if (ret) {
+ pr_err("iommu memory mapping failed ret=%d\n", ret);
} else {
- ret = mdss_iommu_ctrl(1);
- if (IS_ERR_VALUE(ret)) {
- pr_err("mdss iommu attach failed\n");
- mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE,
- mdp5_data->splash_mem_addr,
- mdp5_data->splash_mem_size);
- } else {
- mfd->splash_info.iommu_dynamic_attached = true;
- }
+ pr_debug("iommu map passed for PA=VA\n");
+ mfd->splash_info.iommu_dynamic_attached = true;
}
- return rc;
+ ret = mdss_smmu_set_attribute(MDSS_IOMMU_DOMAIN_UNSECURE, EARLY_MAP, 0);
+end:
+ mdata->handoff_pending = true;
+
+ return ret;
}
static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd)
@@ -194,12 +209,10 @@ static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd)
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
if (mfd->splash_info.iommu_dynamic_attached) {
-
mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE,
mdp5_data->splash_mem_addr,
mdp5_data->splash_mem_size);
mdss_iommu_ctrl(0);
-
mfd->splash_info.iommu_dynamic_attached = false;
}
}
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 75f502415589..02e6d210b6e4 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -280,6 +280,27 @@ end:
return rc;
}
+int mdss_smmu_set_attribute(int domain, int flag, int val)
+{
+ int rc = 0, domain_attr = 0;
+ struct mdss_smmu_client *mdss_smmu = mdss_smmu_get_cb(domain);
+
+ if (!mdss_smmu) {
+ pr_err("not able to get smmu context\n");
+ return -EINVAL;
+ }
+
+ if (flag == EARLY_MAP)
+ domain_attr = DOMAIN_ATTR_EARLY_MAP;
+ else
+ goto end;
+
+ rc = iommu_domain_set_attr(mdss_smmu->mmu_mapping->domain,
+ domain_attr, &val);
+end:
+ return rc;
+}
+
/*
* mdss_smmu_attach_v2()
*
diff --git a/drivers/video/fbdev/msm/mdss_smmu.h b/drivers/video/fbdev/msm/mdss_smmu.h
index a5c7af74cdbf..679e564bcbc9 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.h
+++ b/drivers/video/fbdev/msm/mdss_smmu.h
@@ -48,6 +48,11 @@ struct mdss_smmu_private {
void mdss_smmu_register(struct device *dev);
int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev);
+int mdss_smmu_set_attribute(int domain, int flag, int val);
+
+enum smmu_attributes {
+ EARLY_MAP
+};
static inline int mdss_smmu_dma_data_direction(int dir)
{
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index df2e6f783318..527de56f832f 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -335,8 +335,8 @@ static int mmap_batch_fn(void *data, int nr, void *state)
st->global_error = 1;
}
}
- st->va += PAGE_SIZE * nr;
- st->index += nr;
+ st->va += XEN_PAGE_SIZE * nr;
+ st->index += nr / XEN_PFN_PER_PAGE;
return 0;
}
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 2a2e370399ba..c36a03fa7678 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3854,6 +3854,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
info->space_info_kobj, "%s",
alloc_name(found->flags));
if (ret) {
+ percpu_counter_destroy(&found->total_bytes_pinned);
kfree(found);
return ret;
}
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 353f4bae658c..d4a6eef31854 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2771,7 +2771,7 @@ static long btrfs_fallocate(struct file *file, int mode,
if (!ret)
ret = btrfs_prealloc_file_range(inode, mode,
range->start,
- range->len, 1 << inode->i_blkbits,
+ range->len, i_blocksize(inode),
offset + len, &alloc_hint);
list_del(&range->list);
kfree(range);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3cff6523f27d..863fa0f1972b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7318,8 +7318,8 @@ bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end)
int found = false;
void **pagep = NULL;
struct page *page = NULL;
- int start_idx;
- int end_idx;
+ unsigned long start_idx;
+ unsigned long end_idx;
start_idx = start >> PAGE_CACHE_SHIFT;
diff --git a/fs/buffer.c b/fs/buffer.c
index fc35dd27cc0f..14ce7b24f32a 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2347,7 +2347,7 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
loff_t pos, loff_t *bytes)
{
struct inode *inode = mapping->host;
- unsigned blocksize = 1 << inode->i_blkbits;
+ unsigned int blocksize = i_blocksize(inode);
struct page *page;
void *fsdata;
pgoff_t index, curidx;
@@ -2427,8 +2427,8 @@ int cont_write_begin(struct file *file, struct address_space *mapping,
get_block_t *get_block, loff_t *bytes)
{
struct inode *inode = mapping->host;
- unsigned blocksize = 1 << inode->i_blkbits;
- unsigned zerofrom;
+ unsigned int blocksize = i_blocksize(inode);
+ unsigned int zerofrom;
int err;
err = cont_expand_zero(file, mapping, pos, bytes);
@@ -2790,7 +2790,7 @@ int nobh_truncate_page(struct address_space *mapping,
struct buffer_head map_bh;
int err;
- blocksize = 1 << inode->i_blkbits;
+ blocksize = i_blocksize(inode);
length = offset & (blocksize - 1);
/* Block boundary? Nothing to do */
@@ -2868,7 +2868,7 @@ int block_truncate_page(struct address_space *mapping,
struct buffer_head *bh;
int err;
- blocksize = 1 << inode->i_blkbits;
+ blocksize = i_blocksize(inode);
length = offset & (blocksize - 1);
/* Block boundary? Nothing to do */
@@ -2980,7 +2980,7 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block,
struct inode *inode = mapping->host;
tmp.b_state = 0;
tmp.b_blocknr = 0;
- tmp.b_size = 1 << inode->i_blkbits;
+ tmp.b_size = i_blocksize(inode);
get_block(inode, block, &tmp, 0);
return tmp.b_blocknr;
}
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index b7d218a168fb..c6a1ec110c01 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -697,7 +697,7 @@ static int ceph_writepages_start(struct address_space *mapping,
struct pagevec pvec;
int done = 0;
int rc = 0;
- unsigned wsize = 1 << inode->i_blkbits;
+ unsigned int wsize = i_blocksize(inode);
struct ceph_osd_request *req = NULL;
int do_sync = 0;
loff_t snap_size, i_size;
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 0f1517d0b969..7cdf8ad1bb5b 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -589,7 +589,7 @@ static int dio_set_defer_completion(struct dio *dio)
/*
* Call into the fs to map some more disk blocks. We record the current number
* of available blocks at sdio->blocks_available. These are in units of the
- * fs blocksize, (1 << inode->i_blkbits).
+ * fs blocksize, i_blocksize(inode).
*
* The fs is allowed to map lots of blocks at once. If it wants to do that,
* it uses the passed inode-relative block number as the file offset, as usual.
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 8a456f9b8a44..61d5bfc7318c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4902,6 +4902,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
/* Zero out partial block at the edges of the range */
ret = ext4_zero_partial_blocks(handle, inode, offset, len);
+ if (ret >= 0)
+ ext4_update_inode_fsync_trans(handle, inode, 1);
if (file->f_flags & O_SYNC)
ext4_handle_sync(handle);
@@ -5597,6 +5599,7 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
ext4_handle_sync(handle);
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
+ ext4_update_inode_fsync_trans(handle, inode, 1);
out_stop:
ext4_journal_stop(handle);
@@ -5770,6 +5773,8 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
up_write(&EXT4_I(inode)->i_data_sem);
if (IS_SYNC(inode))
ext4_handle_sync(handle);
+ if (ret >= 0)
+ ext4_update_inode_fsync_trans(handle, inode, 1);
out_stop:
ext4_journal_stop(handle);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 0d24ebcd7c9e..8772bfc3415b 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -463,47 +463,27 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
num = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
(pgoff_t)num);
- if (nr_pages == 0) {
- if (whence == SEEK_DATA)
- break;
-
- BUG_ON(whence != SEEK_HOLE);
- /*
- * If this is the first time to go into the loop and
- * offset is not beyond the end offset, it will be a
- * hole at this offset
- */
- if (lastoff == startoff || lastoff < endoff)
- found = 1;
+ if (nr_pages == 0)
break;
- }
-
- /*
- * If this is the first time to go into the loop and
- * offset is smaller than the first page offset, it will be a
- * hole at this offset.
- */
- if (lastoff == startoff && whence == SEEK_HOLE &&
- lastoff < page_offset(pvec.pages[0])) {
- found = 1;
- break;
- }
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
struct buffer_head *bh, *head;
/*
- * If the current offset is not beyond the end of given
- * range, it will be a hole.
+ * If current offset is smaller than the page offset,
+ * there is a hole at this offset.
*/
- if (lastoff < endoff && whence == SEEK_HOLE &&
- page->index > end) {
+ if (whence == SEEK_HOLE && lastoff < endoff &&
+ lastoff < page_offset(pvec.pages[i])) {
found = 1;
*offset = lastoff;
goto out;
}
+ if (page->index > end)
+ goto out;
+
lock_page(page);
if (unlikely(page->mapping != inode->i_mapping)) {
@@ -543,20 +523,18 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
unlock_page(page);
}
- /*
- * The no. of pages is less than our desired, that would be a
- * hole in there.
- */
- if (nr_pages < num && whence == SEEK_HOLE) {
- found = 1;
- *offset = lastoff;
+ /* The no. of pages is less than our desired, we are done. */
+ if (nr_pages < num)
break;
- }
index = pvec.pages[i - 1]->index + 1;
pagevec_release(&pvec);
} while (index <= end);
+ if (whence == SEEK_HOLE && lastoff < endoff) {
+ found = 1;
+ *offset = lastoff;
+ }
out:
pagevec_release(&pvec);
return found;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2892a799f6f8..521abc5c743d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2059,7 +2059,7 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
{
struct inode *inode = mpd->inode;
int err;
- ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1)
+ ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1)
>> inode->i_blkbits;
do {
@@ -3855,6 +3855,8 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
+ if (ret >= 0)
+ ext4_update_inode_fsync_trans(handle, inode, 1);
out_stop:
ext4_journal_stop(handle);
out_dio:
@@ -5230,8 +5232,9 @@ static int ext4_expand_extra_isize(struct inode *inode,
/* No extended attributes present */
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
- memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
- new_extra_isize);
+ memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
+ EXT4_I(inode)->i_extra_isize, 0,
+ new_extra_isize - EXT4_I(inode)->i_extra_isize);
EXT4_I(inode)->i_extra_isize = new_extra_isize;
return 0;
}
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 7861d801b048..05048fcfd602 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -187,7 +187,7 @@ mext_page_mkuptodate(struct page *page, unsigned from, unsigned to)
if (PageUptodate(page))
return 0;
- blocksize = 1 << inode->i_blkbits;
+ blocksize = i_blocksize(inode);
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 8f9176caf098..c8d58c5ac8ae 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -758,7 +758,7 @@ static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,
sb->s_blocksize - offset : toread;
tmp_bh.b_state = 0;
- tmp_bh.b_size = 1 << inode->i_blkbits;
+ tmp_bh.b_size = i_blocksize(inode);
err = jfs_get_block(inode, blk, &tmp_bh, 0);
if (err)
return err;
@@ -798,7 +798,7 @@ static ssize_t jfs_quota_write(struct super_block *sb, int type,
sb->s_blocksize - offset : towrite;
tmp_bh.b_state = 0;
- tmp_bh.b_size = 1 << inode->i_blkbits;
+ tmp_bh.b_size = i_blocksize(inode);
err = jfs_get_block(inode, blk, &tmp_bh, 1);
if (err)
goto out;
diff --git a/fs/mbcache.c b/fs/mbcache.c
index ab1da987d1ae..de509271d031 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -222,8 +222,19 @@ __mb_cache_entry_release(struct mb_cache_entry *ce)
* then reacquire the lock in the proper order.
*/
spin_lock(&mb_cache_spinlock);
- if (list_empty(&ce->e_lru_list))
- list_add_tail(&ce->e_lru_list, &mb_cache_lru_list);
+ /*
+ * Evaluate the conditions under global lock mb_cache_spinlock,
+ * to check if mb_cache_entry_get() is running now
+ * and has already deleted the entry from mb_cache_lru_list
+ * and incremented ce->e_refcnt to prevent further additions
+ * to mb_cache_lru_list.
+ */
+ if (!(ce->e_used || ce->e_queued ||
+ atomic_read(&ce->e_refcnt))) {
+ if (list_empty(&ce->e_lru_list))
+ list_add_tail(&ce->e_lru_list,
+ &mb_cache_lru_list);
+ }
spin_unlock(&mb_cache_spinlock);
}
__spin_unlock_mb_cache_entry(ce);
diff --git a/fs/mpage.c b/fs/mpage.c
index 0fd48fdcc1b1..f37bb01a333b 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -147,7 +147,7 @@ map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block)
SetPageUptodate(page);
return;
}
- create_empty_buffers(page, 1 << inode->i_blkbits, 0);
+ create_empty_buffers(page, i_blocksize(inode), 0);
}
head = page_buffers(page);
page_bh = head;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 52ee0b73ab4a..5b21b1ca2341 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2421,6 +2421,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
}
EXPORT_SYMBOL_GPL(nfs_may_open);
+static int nfs_execute_ok(struct inode *inode, int mask)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ int ret;
+
+ if (mask & MAY_NOT_BLOCK)
+ ret = nfs_revalidate_inode_rcu(server, inode);
+ else
+ ret = nfs_revalidate_inode(server, inode);
+ if (ret == 0 && !execute_ok(inode))
+ ret = -EACCES;
+ return ret;
+}
+
int nfs_permission(struct inode *inode, int mask)
{
struct rpc_cred *cred;
@@ -2438,6 +2452,9 @@ int nfs_permission(struct inode *inode, int mask)
case S_IFLNK:
goto out;
case S_IFREG:
+ if ((mask & MAY_OPEN) &&
+ nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN))
+ return 0;
break;
case S_IFDIR:
/*
@@ -2470,8 +2487,8 @@ force_lookup:
res = PTR_ERR(cred);
}
out:
- if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
- res = -EACCES;
+ if (!res && (mask & MAY_EXEC))
+ res = nfs_execute_ok(inode, mask);
dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res);
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index c29d9421bd5e..0976f8dad4ce 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -50,7 +50,7 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
{
struct nfsd4_layout_seg *seg = &args->lg_seg;
struct super_block *sb = inode->i_sb;
- u32 block_size = (1 << inode->i_blkbits);
+ u32 block_size = i_blocksize(inode);
struct pnfs_block_extent *bex;
struct iomap iomap;
u32 device_generation = 0;
@@ -151,7 +151,7 @@ nfsd4_block_proc_layoutcommit(struct inode *inode,
int error;
nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
- lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
+ lcp->lc_up_len, &iomaps, i_blocksize(inode));
if (nr_iomaps < 0)
return nfserrno(nr_iomaps);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7d5351cd67fb..209dbfc50cd4 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1690,6 +1690,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
opdesc->op_get_currentstateid(cstate, &op->u);
op->status = opdesc->op_func(rqstp, cstate, &op->u);
+ /* Only from SEQUENCE */
+ if (cstate->status == nfserr_replay_cache) {
+ dprintk("%s NFS4.1 replay from cache\n", __func__);
+ status = op->status;
+ goto out;
+ }
if (!op->status) {
if (opdesc->op_set_currentstateid)
opdesc->op_set_currentstateid(cstate, &op->u);
@@ -1700,14 +1706,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
if (need_wrongsec_check(rqstp))
op->status = check_nfsd_access(current_fh->fh_export, rqstp);
}
-
encode_op:
- /* Only from SEQUENCE */
- if (cstate->status == nfserr_replay_cache) {
- dprintk("%s NFS4.1 replay from cache\n", __func__);
- status = op->status;
- goto out;
- }
if (op->status == nfserr_replay_me) {
op->replay = &cstate->replay_owner->so_replay;
nfsd4_encode_replay(&resp->xdr, op);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c3e1cb481fe0..3f68a25f2169 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2753,9 +2753,16 @@ out_acl:
}
#endif /* CONFIG_NFSD_PNFS */
if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
- status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0,
- NFSD_SUPPATTR_EXCLCREAT_WORD1,
- NFSD_SUPPATTR_EXCLCREAT_WORD2);
+ u32 supp[3];
+
+ supp[0] = nfsd_suppattrs0(minorversion);
+ supp[1] = nfsd_suppattrs1(minorversion);
+ supp[2] = nfsd_suppattrs2(minorversion);
+ supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
+ supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
+ supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
+
+ status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
if (status)
goto out;
}
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c
index a35ae35e6932..cd39b57288c2 100644
--- a/fs/nilfs2/btnode.c
+++ b/fs/nilfs2/btnode.c
@@ -55,7 +55,7 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
brelse(bh);
BUG();
}
- memset(bh->b_data, 0, 1 << inode->i_blkbits);
+ memset(bh->b_data, 0, i_blocksize(inode));
bh->b_bdev = inode->i_sb->s_bdev;
bh->b_blocknr = blocknr;
set_buffer_mapped(bh);
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index ac2f64943ff4..00877ef0b120 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -55,7 +55,7 @@ void nilfs_inode_add_blocks(struct inode *inode, int n)
{
struct nilfs_root *root = NILFS_I(inode)->i_root;
- inode_add_bytes(inode, (1 << inode->i_blkbits) * n);
+ inode_add_bytes(inode, i_blocksize(inode) * n);
if (root)
atomic64_add(n, &root->blocks_count);
}
@@ -64,7 +64,7 @@ void nilfs_inode_sub_blocks(struct inode *inode, int n)
{
struct nilfs_root *root = NILFS_I(inode)->i_root;
- inode_sub_bytes(inode, (1 << inode->i_blkbits) * n);
+ inode_sub_bytes(inode, i_blocksize(inode) * n);
if (root)
atomic64_sub(n, &root->blocks_count);
}
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index 1125f40233ff..612a2457243d 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -60,7 +60,7 @@ nilfs_mdt_insert_new_block(struct inode *inode, unsigned long block,
set_buffer_mapped(bh);
kaddr = kmap_atomic(bh->b_page);
- memset(kaddr + bh_offset(bh), 0, 1 << inode->i_blkbits);
+ memset(kaddr + bh_offset(bh), 0, i_blocksize(inode));
if (init_block)
init_block(inode, bh, kaddr);
flush_dcache_page(bh->b_page);
@@ -503,7 +503,7 @@ void nilfs_mdt_set_entry_size(struct inode *inode, unsigned entry_size,
struct nilfs_mdt_info *mi = NILFS_MDT(inode);
mi->mi_entry_size = entry_size;
- mi->mi_entries_per_block = (1 << inode->i_blkbits) / entry_size;
+ mi->mi_entries_per_block = i_blocksize(inode) / entry_size;
mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size);
}
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index 3b65adaae7e4..2f27c935bd57 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -719,7 +719,7 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode,
lock_page(page);
if (!page_has_buffers(page))
- create_empty_buffers(page, 1 << inode->i_blkbits, 0);
+ create_empty_buffers(page, i_blocksize(inode), 0);
unlock_page(page);
bh = head = page_buffers(page);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index e6795c7c76a8..e4184bd2a954 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -1103,7 +1103,7 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
int ret = 0;
struct buffer_head *head, *bh, *wait[2], **wait_bh = wait;
unsigned int block_end, block_start;
- unsigned int bsize = 1 << inode->i_blkbits;
+ unsigned int bsize = i_blocksize(inode);
if (!page_has_buffers(page))
create_empty_buffers(page, bsize, 0);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 56dd3957cc91..1d738723a41a 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -808,7 +808,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
/* We know that zero_from is block aligned */
for (block_start = zero_from; block_start < zero_to;
block_start = block_end) {
- block_end = block_start + (1 << inode->i_blkbits);
+ block_end = block_start + i_blocksize(inode);
/*
* block_start is block-aligned. Bump it by one to force
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 8f5ccdf81c25..38187300a2b4 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -189,7 +189,7 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
int ret = 0;
th.t_trans_id = 0;
- blocksize = 1 << inode->i_blkbits;
+ blocksize = i_blocksize(inode);
if (logit) {
reiserfs_write_lock(s);
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 3d8e7e671d5b..60ba35087d12 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -524,7 +524,7 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode,
* referenced in convert_tail_for_hole() that may be called from
* reiserfs_get_block()
*/
- bh_result->b_size = (1 << inode->i_blkbits);
+ bh_result->b_size = i_blocksize(inode);
ret = reiserfs_get_block(inode, iblock, bh_result,
create | GET_BLOCK_NO_DANGLE);
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
index 00ae21151f52..676e394e07be 100644
--- a/fs/sdcardfs/lookup.c
+++ b/fs/sdcardfs/lookup.c
@@ -199,7 +199,8 @@ static struct dentry *__sdcardfs_interpose(struct dentry *dentry,
ret_dentry = d_splice_alias(inode, dentry);
dentry = ret_dentry ?: dentry;
- update_derived_permission_lock(dentry);
+ if (!IS_ERR(dentry))
+ update_derived_permission_lock(dentry);
out:
return ret_dentry;
}
diff --git a/fs/stat.c b/fs/stat.c
index d4a61d8dc021..004dd77c3b93 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -31,7 +31,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
stat->atime = inode->i_atime;
stat->mtime = inode->i_mtime;
stat->ctime = inode->i_ctime;
- stat->blksize = (1 << inode->i_blkbits);
+ stat->blksize = i_blocksize(inode);
stat->blocks = inode->i_blocks;
}
@@ -454,6 +454,7 @@ void __inode_add_bytes(struct inode *inode, loff_t bytes)
inode->i_bytes -= 512;
}
}
+EXPORT_SYMBOL(__inode_add_bytes);
void inode_add_bytes(struct inode *inode, loff_t bytes)
{
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 566df9b5a6cb..7be3166ba553 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1206,7 +1206,7 @@ int udf_setsize(struct inode *inode, loff_t newsize)
{
int err;
struct udf_inode_info *iinfo;
- int bsize = 1 << inode->i_blkbits;
+ int bsize = i_blocksize(inode);
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index dc5fae601c24..637e17cb0edd 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -81,7 +81,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
ufs_error (sb, "ufs_free_fragments",
"bit already cleared for fragment %u", i);
}
-
+
+ inode_sub_bytes(inode, count << uspi->s_fshift);
fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
uspi->cs_total.cs_nffree += count;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -183,6 +184,7 @@ do_more:
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+ inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1);
@@ -494,6 +496,20 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
return 0;
}
+static bool try_add_frags(struct inode *inode, unsigned frags)
+{
+ unsigned size = frags * i_blocksize(inode);
+ spin_lock(&inode->i_lock);
+ __inode_add_bytes(inode, size);
+ if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
+ __inode_sub_bytes(inode, size);
+ spin_unlock(&inode->i_lock);
+ return false;
+ }
+ spin_unlock(&inode->i_lock);
+ return true;
+}
+
static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
unsigned oldcount, unsigned newcount)
{
@@ -530,6 +546,9 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
for (i = oldcount; i < newcount; i++)
if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
return 0;
+
+ if (!try_add_frags(inode, count))
+ return 0;
/*
* Block can be extended
*/
@@ -647,6 +666,7 @@ cg_found:
ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
i = uspi->s_fpb - count;
+ inode_sub_bytes(inode, i << uspi->s_fshift);
fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
uspi->cs_total.cs_nffree += i;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
@@ -657,6 +677,8 @@ cg_found:
result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
if (result == INVBLOCK)
return 0;
+ if (!try_add_frags(inode, count))
+ return 0;
for (i = 0; i < count; i++)
ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
@@ -716,6 +738,8 @@ norot:
return INVBLOCK;
ucpi->c_rotor = result;
gotit:
+ if (!try_add_frags(inode, uspi->s_fpb))
+ return 0;
blkno = ufs_fragstoblks(result);
ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index a064cf44b143..1f69bb9b1e9d 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -235,7 +235,8 @@ ufs_extend_tail(struct inode *inode, u64 writes_to,
p = ufs_get_direct_data_ptr(uspi, ufsi, block);
tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p),
- new_size, err, locked_page);
+ new_size - (lastfrag & uspi->s_fpbmask), err,
+ locked_page);
return tmp != 0;
}
@@ -284,7 +285,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index,
goal += uspi->s_fpb;
}
tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment),
- goal, uspi->s_fpb, err, locked_page);
+ goal, nfrags, err, locked_page);
if (!tmp) {
*err = -ENOSPC;
@@ -402,7 +403,9 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff
if (!create) {
phys64 = ufs_frag_map(inode, offsets, depth);
- goto out;
+ if (phys64)
+ map_bh(bh_result, sb, phys64 + frag);
+ return 0;
}
/* This code entered only while writing ....? */
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index f6390eec02ca..10f364490833 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -746,6 +746,23 @@ static void ufs_put_super(struct super_block *sb)
return;
}
+static u64 ufs_max_bytes(struct super_block *sb)
+{
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+ int bits = uspi->s_apbshift;
+ u64 res;
+
+ if (bits > 21)
+ res = ~0ULL;
+ else
+ res = UFS_NDADDR + (1LL << bits) + (1LL << (2*bits)) +
+ (1LL << (3*bits));
+
+ if (res >= (MAX_LFS_FILESIZE >> uspi->s_bshift))
+ return MAX_LFS_FILESIZE;
+ return res << uspi->s_bshift;
+}
+
static int ufs_fill_super(struct super_block *sb, void *data, int silent)
{
struct ufs_sb_info * sbi;
@@ -1212,6 +1229,7 @@ magic_found:
"fast symlink size (%u)\n", uspi->s_maxsymlinklen);
uspi->s_maxsymlinklen = maxsymlen;
}
+ sb->s_maxbytes = ufs_max_bytes(sb);
sb->s_max_links = UFS_LINK_MAX;
inode = ufs_iget(sb, UFS_ROOTINO);
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 954175928240..3f9463f8cf2f 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -473,15 +473,19 @@ static inline unsigned _ubh_find_last_zero_bit_(
static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
{
+ u8 mask;
switch (uspi->s_fpb) {
case 8:
return (*ubh_get_addr (ubh, begin + block) == 0xff);
case 4:
- return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2)));
+ mask = 0x0f << ((block & 0x01) << 2);
+ return (*ubh_get_addr (ubh, begin + (block >> 1)) & mask) == mask;
case 2:
- return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1)));
+ mask = 0x03 << ((block & 0x03) << 1);
+ return (*ubh_get_addr (ubh, begin + (block >> 2)) & mask) == mask;
case 1:
- return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07)));
+ mask = 0x01 << (block & 0x07);
+ return (*ubh_get_addr (ubh, begin + (block >> 3)) & mask) == mask;
}
return 0;
}
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 29e7e5dd5178..187b80267ff9 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -288,7 +288,7 @@ xfs_map_blocks(
{
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
- ssize_t count = 1 << inode->i_blkbits;
+ ssize_t count = i_blocksize(inode);
xfs_fileoff_t offset_fsb, end_fsb;
int error = 0;
int bmapi_flags = XFS_BMAPI_ENTIRE;
@@ -921,7 +921,7 @@ xfs_aops_discard_page(
break;
}
next_buffer:
- offset += 1 << inode->i_blkbits;
+ offset += i_blocksize(inode);
} while ((bh = bh->b_this_page) != head);
@@ -1363,7 +1363,7 @@ xfs_map_trim_size(
offset + mapping_size >= i_size_read(inode)) {
/* limit mapping to block that spans EOF */
mapping_size = roundup_64(i_size_read(inode) - offset,
- 1 << inode->i_blkbits);
+ i_blocksize(inode));
}
if (mapping_size > LONG_MAX)
mapping_size = LONG_MAX;
@@ -1395,7 +1395,7 @@ __xfs_get_blocks(
return -EIO;
offset = (xfs_off_t)iblock << inode->i_blkbits;
- ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
+ ASSERT(bh_result->b_size >= i_blocksize(inode));
size = bh_result->b_size;
if (!create && direct && offset >= i_size_read(inode))
@@ -1968,7 +1968,7 @@ xfs_vm_set_page_dirty(
if (offset < end_offset)
set_buffer_dirty(bh);
bh = bh->b_this_page;
- offset += 1 << inode->i_blkbits;
+ offset += i_blocksize(inode);
} while (bh != head);
}
/*
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index ceea444dafb4..3dd47307363f 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -947,7 +947,7 @@ xfs_file_fallocate(
if (error)
goto out_unlock;
} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
- unsigned blksize_mask = (1 << inode->i_blkbits) - 1;
+ unsigned int blksize_mask = i_blocksize(inode) - 1;
if (offset & blksize_mask || len & blksize_mask) {
error = -EINVAL;
@@ -969,7 +969,7 @@ xfs_file_fallocate(
if (error)
goto out_unlock;
} else if (mode & FALLOC_FL_INSERT_RANGE) {
- unsigned blksize_mask = (1 << inode->i_blkbits) - 1;
+ unsigned int blksize_mask = i_blocksize(inode) - 1;
new_size = i_size_read(inode) + len;
if (offset & blksize_mask || len & blksize_mask) {
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index e6dae28dfa1a..9beaf192b4bb 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -180,6 +180,7 @@ xfs_xattr_put_listent(
arraytop = context->count + prefix_len + namelen + 1;
if (arraytop > context->firstu) {
context->count = -1; /* insufficient space */
+ context->seen_enough = 1;
return 0;
}
offset = (char *)context->alist + context->count;
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index ad2bcf647b9a..210ccc4ea44b 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -340,6 +340,26 @@ static inline bool css_tryget_online(struct cgroup_subsys_state *css)
}
/**
+ * css_is_dying - test whether the specified css is dying
+ * @css: target css
+ *
+ * Test whether @css is in the process of offlining or already offline. In
+ * most cases, ->css_online() and ->css_offline() callbacks should be
+ * enough; however, the actual offline operations are RCU delayed and this
+ * test returns %true also when @css is scheduled to be offlined.
+ *
+ * This is useful, for example, when the use case requires synchronous
+ * behavior with respect to cgroup removal. cgroup removal schedules css
+ * offlining but the css can seem alive while the operation is being
+ * delayed. If the delay affects user visible semantics, this test can be
+ * used to resolve the situation.
+ */
+static inline bool css_is_dying(struct cgroup_subsys_state *css)
+{
+ return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
+}
+
+/**
* css_put - put a css reference
* @css: target css
*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 28c8f7038ae0..4b27be2038e3 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -689,6 +689,11 @@ struct inode {
void *i_private; /* fs or device private pointer */
};
+static inline unsigned int i_blocksize(const struct inode *node)
+{
+ return (1 << node->i_blkbits);
+}
+
static inline int inode_unhashed(struct inode *inode)
{
return hlist_unhashed(&inode->i_hash);
diff --git a/include/linux/ipc_router.h b/include/linux/ipc_router.h
index 04a06df66d4b..94f779f6a666 100644
--- a/include/linux/ipc_router.h
+++ b/include/linux/ipc_router.h
@@ -144,6 +144,7 @@ struct msm_ipc_port {
uint32_t num_rx;
unsigned long num_tx_bytes;
unsigned long num_rx_bytes;
+ uint32_t last_served_svc_id;
void *priv;
};
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index ab93174fa639..d4b56351027b 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -424,12 +424,20 @@ static inline void early_memtest(phys_addr_t start, phys_addr_t end)
}
#endif
+extern unsigned long memblock_reserved_memory_within(phys_addr_t start_addr,
+ phys_addr_t end_addr);
#else
static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align)
{
return 0;
}
+static inline unsigned long memblock_reserved_memory_within(phys_addr_t start_addr,
+ phys_addr_t end_addr)
+{
+ return 0;
+}
+
#endif /* CONFIG_HAVE_MEMBLOCK */
#endif /* __KERNEL__ */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ad7f915ddf76..9d1161a8d6b7 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -712,6 +712,7 @@ typedef struct pglist_data {
* is the first PFN that needs to be initialised.
*/
unsigned long first_deferred_pfn;
+ unsigned long static_init_size;
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
} pg_data_t;
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index d4b4cc7f8737..b95ea88c2424 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -749,6 +749,18 @@ int gsi_query_evt_ring_db_addr(unsigned long evt_ring_hdl,
uint32_t *db_addr_wp_lsb, uint32_t *db_addr_wp_msb);
/**
+ * gsi_ring_evt_ring_db - Peripheral should call this function for
+ * ringing the event ring doorbell with given value
+ *
+ * @evt_ring_hdl: Client handle previously obtained from
+ * gsi_alloc_evt_ring
+ * @value: The value to be used for ringing the doorbell
+ *
+ * @Return gsi_status
+ */
+int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value);
+
+/**
* gsi_reset_evt_ring - Peripheral should call this function to
* reset an event ring to recover from error state
*
@@ -1138,6 +1150,12 @@ static inline int gsi_query_evt_ring_db_addr(unsigned long evt_ring_hdl,
return -GSI_STATUS_UNSUPPORTED_OP;
}
+static inline int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl,
+ uint64_t value)
+{
+ return -GSI_STATUS_UNSUPPORTED_OP;
+}
+
static inline int gsi_reset_evt_ring(unsigned long evt_ring_hdl)
{
return -GSI_STATUS_UNSUPPORTED_OP;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 5cc13e9fbd8f..b584e353306d 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -271,6 +271,7 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_USB_HVDCP_3, /* Efficient High Voltage DCP */
POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery */
POWER_SUPPLY_TYPE_WIRELESS, /* Accessory Charger Adapters */
+ POWER_SUPPLY_TYPE_USB_FLOAT, /* Floating charger */
POWER_SUPPLY_TYPE_BMS, /* Battery Monitor System */
POWER_SUPPLY_TYPE_PARALLEL, /* Parallel Path */
POWER_SUPPLY_TYPE_MAIN, /* Main Path */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index e13bfdf7f314..81fdf4b8aba4 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -50,7 +50,8 @@ extern int ptrace_request(struct task_struct *child, long request,
unsigned long addr, unsigned long data);
extern void ptrace_notify(int exit_code);
extern void __ptrace_link(struct task_struct *child,
- struct task_struct *new_parent);
+ struct task_struct *new_parent,
+ const struct cred *ptracer_cred);
extern void __ptrace_unlink(struct task_struct *child);
extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
#define PTRACE_MODE_READ 0x01
@@ -202,7 +203,7 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
if (unlikely(ptrace) && current->ptrace) {
child->ptrace = current->ptrace;
- __ptrace_link(child, current->parent);
+ __ptrace_link(child, current->parent, current->ptracer_cred);
if (child->ptrace & PT_SEIZED)
task_set_jobctl_pending(child, JOBCTL_TRAP_STOP);
@@ -211,6 +212,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
set_tsk_thread_flag(child, TIF_SIGPENDING);
}
+ else
+ child->ptracer_cred = NULL;
}
/**
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index d443d9ab0236..3f61c647fc5c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1084,9 +1084,6 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
static inline void skb_sender_cpu_clear(struct sk_buff *skb)
{
-#ifdef CONFIG_XPS
- skb->sender_cpu = 0;
-#endif
}
#ifdef NET_SKBUFF_DATA_USES_OFFSET
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a55f127d6836..e8b2ed4ad851 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -330,6 +330,8 @@ struct usb_host_bos {
struct usb_ss_cap_descriptor *ss_cap;
struct usb_ssp_cap_descriptor *ssp_cap;
struct usb_ss_container_id_descriptor *ss_id;
+ struct usb_config_summary_descriptor *config_summary;
+ unsigned int num_config_summary_desc;
};
int __usb_get_extra_descriptor(char *buffer, unsigned size,
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 9a5c9f013784..ad1d6039185d 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -958,6 +958,7 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row,
*/
extern const struct proto_ops inet6_stream_ops;
extern const struct proto_ops inet6_dgram_ops;
+extern const struct proto_ops inet6_sockraw_ops;
struct group_source_req;
struct group_filter;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 7f203a5f83cb..b3a2c62da965 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -241,8 +241,23 @@ extern "C" {
*/
#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1)
+/*
+ * QTI DX Format
+ *
+ * Refers to a DX variant of the base format.
+ * Implementation may be platform and base-format specific.
+ */
+#define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2)
+
+/*
+ * QTI Tight Format
+ *
+ * Refers to a tightly packed variant of the base format.
+ * Implementation may be platform and base-format specific.
+ */
+#define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4)
+
#if defined(__cplusplus)
}
#endif
-
#endif /* DRM_FOURCC_H */
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index d8b8ef16b14a..a60e84ab905b 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -62,6 +62,41 @@ struct drm_msm_timespec {
__s64 tv_nsec; /* nanoseconds */
};
+/*
+ * HDR Metadata
+ * These are defined as per EDID spec and shall be used by the sink
+ * to set the HDR metadata for playback from userspace.
+ */
+
+#define HDR_PRIMARIES_COUNT 3
+
+struct drm_msm_ext_panel_hdr_metadata {
+ __u32 eotf; /* electro optical transfer function */
+ __u32 hdr_supported; /* HDR supported */
+ __u32 display_primaries_x[HDR_PRIMARIES_COUNT]; /* Primaries x */
+ __u32 display_primaries_y[HDR_PRIMARIES_COUNT]; /* Primaries y */
+ __u32 white_point_x; /* white_point_x */
+ __u32 white_point_y; /* white_point_y */
+ __u32 max_luminance; /* Max luminance */
+ __u32 min_luminance; /* Min Luminance */
+ __u32 max_content_light_level; /* max content light level */
+ __u32 max_average_light_level; /* max average light level */
+};
+
+/**
+ * HDR sink properties
+ * These are defined as per EDID spec and shall be used by the userspace
+ * to determine the HDR properties to be set to the sink.
+ */
+struct drm_msm_ext_panel_hdr_properties {
+ __u8 hdr_metadata_type_one; /* static metadata type one */
+ __u32 hdr_supported; /* HDR supported */
+ __u32 hdr_eotf; /* electro optical transfer function */
+ __u32 hdr_max_luminance; /* Max luminance */
+ __u32 hdr_avg_luminance; /* Avg luminance */
+ __u32 hdr_min_luminance; /* Min Luminance */
+};
+
#define MSM_PARAM_GPU_ID 0x01
#define MSM_PARAM_GMEM_SIZE 0x02
#define MSM_PARAM_CHIP_ID 0x03
diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h
index 779a62aafafe..d3ab3f57aa9f 100644
--- a/include/uapi/linux/usb/ch9.h
+++ b/include/uapi/linux/usb/ch9.h
@@ -894,6 +894,29 @@ struct usb_ssp_cap_descriptor {
#define USB_SSP_SUBLINK_SPEED_LSM (0xff << 16) /* Lanespeed mantissa */
} __attribute__((packed));
+/*
+ * Configuration Summary descriptors: Defines a list of functions in the
+ * configuration. This descriptor may be used by Host software to decide
+ * which Configuration to use to obtain the desired functionality.
+ */
+#define USB_CAP_TYPE_CONFIG_SUMMARY 0x10
+
+struct function_class_info {
+ __u8 bClass;
+ __u8 bSubClass;
+ __u8 bProtocol;
+};
+
+struct usb_config_summary_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDevCapabilityType;
+ __u16 bcdVersion;
+ __u8 bConfigurationValue;
+ __u8 bMaxPower;
+ __u8 bNumFunctions;
+ struct function_class_info cs_info[];
+} __attribute__((packed));
/*-------------------------------------------------------------------------*/
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 29c7240172d3..03dbc231a4a0 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -174,9 +174,9 @@ typedef enum {
} cpuset_flagbits_t;
/* convenient tests for these bits */
-static inline bool is_cpuset_online(const struct cpuset *cs)
+static inline bool is_cpuset_online(struct cpuset *cs)
{
- return test_bit(CS_ONLINE, &cs->flags);
+ return test_bit(CS_ONLINE, &cs->flags) && !css_is_dying(&cs->css);
}
static inline int is_cpu_exclusive(const struct cpuset *cs)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 95c447e658f7..7fee87daac56 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1693,33 +1693,7 @@ static int __perf_remove_from_context(void *info)
return 0;
}
-
-#ifdef CONFIG_SMP
-static void perf_retry_remove(struct perf_event *event,
- struct remove_event *rep)
-{
- int up_ret;
- /*
- * CPU was offline. Bring it online so we can
- * gracefully exit a perf context.
- */
- up_ret = cpu_up(event->cpu);
- if (!up_ret)
- /* Try the remove call once again. */
- cpu_function_call(event->cpu, __perf_remove_from_context,
- rep);
- else
- pr_err("Failed to bring up CPU: %d, ret: %d\n",
- event->cpu, up_ret);
-}
-#else
-static void perf_retry_remove(struct perf_event *event,
- struct remove_event *rep)
-{
-}
-#endif
-
- /*
+/*
* Remove the event from a task's (or a CPU's) list of events.
*
* CPU events are removed with a smp call. For task events we only
@@ -1754,9 +1728,6 @@ static void __ref perf_remove_from_context(struct perf_event *event,
*/
ret = cpu_function_call(event->cpu, __perf_remove_from_context,
&re);
- if (ret == -ENXIO)
- perf_retry_remove(event, &re);
-
return;
}
@@ -6595,6 +6566,21 @@ static void perf_log_itrace_start(struct perf_event *event)
perf_output_end(&handle);
}
+static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
+{
+ /*
+ * Due to interrupt latency (AKA "skid"), we may enter the
+ * kernel before taking an overflow, even if the PMU is only
+ * counting user events.
+ * To avoid leaking information to userspace, we must always
+ * reject kernel samples when exclude_kernel is set.
+ */
+ if (event->attr.exclude_kernel && !user_mode(regs))
+ return false;
+
+ return true;
+}
+
/*
* Generic event overflow handling, sampling.
*/
@@ -6642,6 +6628,12 @@ static int __perf_event_overflow(struct perf_event *event,
}
/*
+ * For security, drop the skid kernel samples if necessary.
+ */
+ if (!sample_is_allowed(event, regs))
+ return ret;
+
+ /*
* XXX event_limit might not quite work as expected on inherited
* events
*/
@@ -7117,8 +7109,6 @@ static struct pmu perf_swevent = {
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,
-
- .events_across_hotplug = 1,
};
#ifdef CONFIG_EVENT_TRACING
@@ -7240,8 +7230,6 @@ static struct pmu perf_tracepoint = {
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,
-
- .events_across_hotplug = 1,
};
static inline void perf_tp_register(void)
@@ -7529,8 +7517,6 @@ static struct pmu perf_cpu_clock = {
.start = cpu_clock_event_start,
.stop = cpu_clock_event_stop,
.read = cpu_clock_event_read,
-
- .events_across_hotplug = 1,
};
/*
@@ -7612,8 +7598,6 @@ static struct pmu perf_task_clock = {
.start = task_clock_event_start,
.stop = task_clock_event_stop,
.read = task_clock_event_read,
-
- .events_across_hotplug = 1,
};
static void perf_pmu_nop_void(struct pmu *pmu)
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index 7da5b674d16e..92ce5f4ccc26 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -614,8 +614,6 @@ static struct pmu perf_breakpoint = {
.start = hw_breakpoint_start,
.stop = hw_breakpoint_stop,
.read = hw_breakpoint_pmu_read,
-
- .events_across_hotplug = 1,
};
int __init init_hw_breakpoint(void)
diff --git a/kernel/fork.c b/kernel/fork.c
index 2845c5bdc8e3..246b8a57a32d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -370,7 +370,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
set_task_stack_end_magic(tsk);
#ifdef CONFIG_CC_STACKPROTECTOR
- tsk->stack_canary = get_random_int();
+ tsk->stack_canary = get_random_long();
#endif
/*
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index c7e8ed99c953..5e2cd1030702 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -28,19 +28,25 @@
#include <linux/compat.h>
+void __ptrace_link(struct task_struct *child, struct task_struct *new_parent,
+ const struct cred *ptracer_cred)
+{
+ BUG_ON(!list_empty(&child->ptrace_entry));
+ list_add(&child->ptrace_entry, &new_parent->ptraced);
+ child->parent = new_parent;
+ child->ptracer_cred = get_cred(ptracer_cred);
+}
+
/*
* ptrace a task: make the debugger its new parent and
* move it to the ptrace list.
*
* Must be called with the tasklist lock write-held.
*/
-void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
+static void ptrace_link(struct task_struct *child, struct task_struct *new_parent)
{
- BUG_ON(!list_empty(&child->ptrace_entry));
- list_add(&child->ptrace_entry, &new_parent->ptraced);
- child->parent = new_parent;
rcu_read_lock();
- child->ptracer_cred = get_cred(__task_cred(new_parent));
+ __ptrace_link(child, new_parent, __task_cred(new_parent));
rcu_read_unlock();
}
@@ -353,7 +359,7 @@ static int ptrace_attach(struct task_struct *task, long request,
flags |= PT_SEIZED;
task->ptrace = flags;
- __ptrace_link(task, current);
+ ptrace_link(task, current);
/* SEIZE doesn't trap tracee on attach */
if (!seize)
@@ -420,7 +426,7 @@ static int ptrace_traceme(void)
*/
if (!ret && !(current->real_parent->flags & PF_EXITING)) {
current->ptrace = PT_PTRACED;
- __ptrace_link(current, current->real_parent);
+ ptrace_link(current, current->real_parent);
}
}
write_unlock_irq(&tasklist_lock);
diff --git a/lib/test_user_copy.c b/lib/test_user_copy.c
index 0ecef3e4690e..5e6db6b1e3bd 100644
--- a/lib/test_user_copy.c
+++ b/lib/test_user_copy.c
@@ -58,7 +58,9 @@ static int __init test_user_copy_init(void)
usermem = (char __user *)user_addr;
bad_usermem = (char *)user_addr;
- /* Legitimate usage: none of these should fail. */
+ /*
+ * Legitimate usage: none of these copies should fail.
+ */
ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
"legitimate copy_from_user failed");
ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
@@ -68,19 +70,33 @@ static int __init test_user_copy_init(void)
ret |= test(put_user(value, (unsigned long __user *)usermem),
"legitimate put_user failed");
- /* Invalid usage: none of these should succeed. */
+ /*
+ * Invalid usage: none of these copies should succeed.
+ */
+
+ /* Reject kernel-to-kernel copies through copy_from_user(). */
ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
PAGE_SIZE),
"illegal all-kernel copy_from_user passed");
+
+#if 0
+ /*
+ * When running with SMAP/PAN/etc, this will Oops the kernel
+ * due to the zeroing of userspace memory on failure. This needs
+ * to be tested in LKDTM instead, since this test module does not
+ * expect to explode.
+ */
ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
PAGE_SIZE),
"illegal reversed copy_from_user passed");
+#endif
ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
PAGE_SIZE),
"illegal all-kernel copy_to_user passed");
ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
PAGE_SIZE),
"illegal reversed copy_to_user passed");
+
ret |= test(!get_user(value, (unsigned long __user *)kmem),
"illegal get_user passed");
ret |= test(!put_user(value, (unsigned long __user *)kmem),
diff --git a/mm/memblock.c b/mm/memblock.c
index 89e74fa82290..351a4840a407 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1688,6 +1688,30 @@ static void __init_memblock memblock_dump(struct memblock_type *type, char *name
}
}
+extern unsigned long __init_memblock
+memblock_reserved_memory_within(phys_addr_t start_addr, phys_addr_t end_addr)
+{
+ struct memblock_type *type = &memblock.reserved;
+ unsigned long size = 0;
+ int idx;
+
+ for (idx = 0; idx < type->cnt; idx++) {
+ struct memblock_region *rgn = &type->regions[idx];
+ phys_addr_t start, end;
+
+ if (rgn->base + rgn->size < start_addr)
+ continue;
+ if (rgn->base > end_addr)
+ continue;
+
+ start = rgn->base;
+ end = start + rgn->size;
+ size += end - start;
+ }
+
+ return size;
+}
+
void __init_memblock __memblock_dump_all(void)
{
pr_info("MEMBLOCK configuration:\n");
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 170c1486e5c9..4fbb23c1cba7 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -274,6 +274,26 @@ int page_group_by_mobility_disabled __read_mostly;
#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
static inline void reset_deferred_meminit(pg_data_t *pgdat)
{
+ unsigned long max_initialise;
+ unsigned long reserved_lowmem;
+
+ /*
+ * Initialise at least 2G of a node but also take into account that
+ * two large system hashes that can take up 1GB for 0.25TB/node.
+ */
+ max_initialise = max(2UL << (30 - PAGE_SHIFT),
+ (pgdat->node_spanned_pages >> 8));
+
+ /*
+ * Compensate the all the memblock reservations (e.g. crash kernel)
+ * from the initial estimation to make sure we will initialize enough
+ * memory to boot.
+ */
+ reserved_lowmem = memblock_reserved_memory_within(pgdat->node_start_pfn,
+ pgdat->node_start_pfn + max_initialise);
+ max_initialise += reserved_lowmem;
+
+ pgdat->static_init_size = min(max_initialise, pgdat->node_spanned_pages);
pgdat->first_deferred_pfn = ULONG_MAX;
}
@@ -307,10 +327,9 @@ static inline bool update_defer_init(pg_data_t *pgdat,
/* Always populate low zones for address-contrained allocations */
if (zone_end < pgdat_end_pfn(pgdat))
return true;
-
/* Initialise at least 2G of the highest zone */
(*nr_initialised)++;
- if (*nr_initialised > (2UL << (30 - PAGE_SHIFT)) &&
+ if ((*nr_initialised > pgdat->static_init_size) &&
(pfn & (PAGES_PER_SECTION - 1)) == 0) {
pgdat->first_deferred_pfn = pfn;
return false;
@@ -5456,7 +5475,6 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
/* pg_data_t should be reset to zero when it's allocated */
WARN_ON(pgdat->nr_zones || pgdat->classzone_idx);
- reset_deferred_meminit(pgdat);
pgdat->node_id = nid;
pgdat->node_start_pfn = node_start_pfn;
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
@@ -5475,6 +5493,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
(unsigned long)pgdat->node_mem_map);
#endif
+ reset_deferred_meminit(pgdat);
free_area_init_core(pgdat);
}
diff --git a/mm/truncate.c b/mm/truncate.c
index 30c2f059a488..8ca20a98c327 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -799,7 +799,7 @@ EXPORT_SYMBOL(truncate_setsize);
*/
void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to)
{
- int bsize = 1 << inode->i_blkbits;
+ int bsize = i_blocksize(inode);
loff_t rounded_from;
struct page *page;
pgoff_t index;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index b8f2eda3381d..d6b4817c4416 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -906,6 +906,7 @@ static void frag_stop(struct seq_file *m, void *arg)
/* Walk all the zones in a node and print using a callback */
static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
+ bool nolock,
void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
{
struct zone *zone;
@@ -916,9 +917,11 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
if (!populated_zone(zone))
continue;
- spin_lock_irqsave(&zone->lock, flags);
+ if (!nolock)
+ spin_lock_irqsave(&zone->lock, flags);
print(m, pgdat, zone);
- spin_unlock_irqrestore(&zone->lock, flags);
+ if (!nolock)
+ spin_unlock_irqrestore(&zone->lock, flags);
}
}
#endif
@@ -954,7 +957,7 @@ static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
static int frag_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
- walk_zones_in_node(m, pgdat, frag_show_print);
+ walk_zones_in_node(m, pgdat, false, frag_show_print);
return 0;
}
@@ -995,7 +998,7 @@ static int pagetypeinfo_showfree(struct seq_file *m, void *arg)
seq_printf(m, "%6d ", order);
seq_putc(m, '\n');
- walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print);
+ walk_zones_in_node(m, pgdat, false, pagetypeinfo_showfree_print);
return 0;
}
@@ -1044,7 +1047,7 @@ static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
seq_printf(m, "%12s ", migratetype_names[mtype]);
seq_putc(m, '\n');
- walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print);
+ walk_zones_in_node(m, pgdat, false, pagetypeinfo_showblockcount_print);
return 0;
}
@@ -1088,7 +1091,11 @@ static void pagetypeinfo_showmixedcount_print(struct seq_file *m,
page = pfn_to_page(pfn);
if (PageBuddy(page)) {
- pfn += (1UL << page_order(page)) - 1;
+ unsigned long freepage_order;
+
+ freepage_order = page_order_unsafe(page);
+ if (freepage_order < MAX_ORDER)
+ pfn += (1UL << freepage_order) - 1;
continue;
}
@@ -1143,7 +1150,7 @@ static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
seq_printf(m, "%12s ", migratetype_names[mtype]);
seq_putc(m, '\n');
- walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print);
+ walk_zones_in_node(m, pgdat, true, pagetypeinfo_showmixedcount_print);
#endif /* CONFIG_PAGE_OWNER */
}
@@ -1276,7 +1283,7 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
static int zoneinfo_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
- walk_zones_in_node(m, pgdat, zoneinfo_show_print);
+ walk_zones_in_node(m, pgdat, false, zoneinfo_show_print);
return 0;
}
@@ -1635,7 +1642,7 @@ static int unusable_show(struct seq_file *m, void *arg)
if (!node_state(pgdat->node_id, N_MEMORY))
return 0;
- walk_zones_in_node(m, pgdat, unusable_show_print);
+ walk_zones_in_node(m, pgdat, false, unusable_show_print);
return 0;
}
@@ -1687,7 +1694,7 @@ static int extfrag_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
- walk_zones_in_node(m, pgdat, extfrag_show_print);
+ walk_zones_in_node(m, pgdat, false, extfrag_show_print);
return 0;
}
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 57be733a99bc..bcb4559e735d 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -166,7 +166,8 @@ static void br_stp_start(struct net_bridge *br)
br_debug(br, "using kernel STP\n");
/* To start timers on any ports left in blocking */
- mod_timer(&br->hello_timer, jiffies + br->hello_time);
+ if (br->dev->flags & IFF_UP)
+ mod_timer(&br->hello_timer, jiffies + br->hello_time);
br_port_state_selection(br);
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 57922df9c250..50e77fe096f4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -184,7 +184,7 @@ EXPORT_SYMBOL(dev_base_lock);
/* protects napi_hash addition/deletion and napi_gen_id */
static DEFINE_SPINLOCK(napi_hash_lock);
-static unsigned int napi_gen_id;
+static unsigned int napi_gen_id = NR_CPUS;
static DEFINE_HASHTABLE(napi_hash, 8);
static seqcount_t devnet_rename_seq;
@@ -3055,7 +3055,9 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev,
int queue_index = 0;
#ifdef CONFIG_XPS
- if (skb->sender_cpu == 0)
+ u32 sender_cpu = skb->sender_cpu - 1;
+
+ if (sender_cpu >= (u32)NR_CPUS)
skb->sender_cpu = raw_smp_processor_id() + 1;
#endif
@@ -4745,25 +4747,22 @@ EXPORT_SYMBOL_GPL(napi_by_id);
void napi_hash_add(struct napi_struct *napi)
{
- if (!test_and_set_bit(NAPI_STATE_HASHED, &napi->state)) {
+ if (test_and_set_bit(NAPI_STATE_HASHED, &napi->state))
+ return;
- spin_lock(&napi_hash_lock);
+ spin_lock(&napi_hash_lock);
- /* 0 is not a valid id, we also skip an id that is taken
- * we expect both events to be extremely rare
- */
- napi->napi_id = 0;
- while (!napi->napi_id) {
- napi->napi_id = ++napi_gen_id;
- if (napi_by_id(napi->napi_id))
- napi->napi_id = 0;
- }
+ /* 0..NR_CPUS+1 range is reserved for sender_cpu use */
+ do {
+ if (unlikely(++napi_gen_id < NR_CPUS + 1))
+ napi_gen_id = NR_CPUS + 1;
+ } while (napi_by_id(napi_gen_id));
+ napi->napi_id = napi_gen_id;
- hlist_add_head_rcu(&napi->napi_hash_node,
- &napi_hash[napi->napi_id % HASH_SIZE(napi_hash)]);
+ hlist_add_head_rcu(&napi->napi_hash_node,
+ &napi_hash[napi->napi_id % HASH_SIZE(napi_hash)]);
- spin_unlock(&napi_hash_lock);
- }
+ spin_unlock(&napi_hash_lock);
}
EXPORT_SYMBOL_GPL(napi_hash_add);
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index f08aef9509bb..5cb309a11f82 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -364,6 +364,8 @@ static void ipc_router_log_msg(void *log_ctx, uint32_t xchng_type,
svcId = rport_ptr->server->name.service;
svcIns = rport_ptr->server->name.instance;
port_type = CLIENT_PORT;
+ port_ptr->last_served_svc_id =
+ rport_ptr->server->name.service;
} else if (port_ptr && (port_ptr->type == SERVER_PORT)) {
svcId = port_ptr->port_name.service;
svcIns = port_ptr->port_name.instance;
@@ -1329,8 +1331,9 @@ struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
mutex_init(&port_ptr->port_rx_q_lock_lhc3);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_ws_name, MAX_WS_NAME_SZ,
- "ipc%08x_%s",
+ "ipc%08x_%d_%s",
port_ptr->this_port.port_id,
+ task_pid_nr(current),
current->comm);
port_ptr->port_rx_ws = wakeup_source_register(port_ptr->rx_ws_name);
if (!port_ptr->port_rx_ws) {
@@ -3867,16 +3870,18 @@ static void dump_local_ports(struct seq_file *s)
int j;
struct msm_ipc_port *port_ptr;
- seq_printf(s, "%-11s|%-11s|\n",
- "Node_id", "Port_id");
+ seq_printf(s, "%-11s|%-11s|%-32s|%-11s|\n",
+ "Node_id", "Port_id", "Wakelock", "Last SVCID");
seq_puts(s, "------------------------------------------------------------\n");
down_read(&local_ports_lock_lhc2);
for (j = 0; j < LP_HASH_SIZE; j++) {
list_for_each_entry(port_ptr, &local_ports[j], list) {
mutex_lock(&port_ptr->port_lock_lhc3);
- seq_printf(s, "0x%08x |0x%08x |\n",
- port_ptr->this_port.node_id,
- port_ptr->this_port.port_id);
+ seq_printf(s, "0x%08x |0x%08x |%-32s|0x%08x |\n",
+ port_ptr->this_port.node_id,
+ port_ptr->this_port.port_id,
+ port_ptr->rx_ws_name,
+ port_ptr->last_served_svc_id);
mutex_unlock(&port_ptr->port_lock_lhc3);
}
}
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index c9ef99fbd0dd..aad274c67b5e 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1035,7 +1035,7 @@ static struct inet_protosw inetsw_array[] =
.type = SOCK_DGRAM,
.protocol = IPPROTO_ICMP,
.prot = &ping_prot,
- .ops = &inet_dgram_ops,
+ .ops = &inet_sockraw_ops,
.flags = INET_PROTOSW_REUSE,
},
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 882caa4e72bc..aafe68134763 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -183,6 +183,7 @@ void tcp_init_congestion_control(struct sock *sk)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
+ tcp_sk(sk)->prior_ssthresh = 0;
if (icsk->icsk_ca_ops->init)
icsk->icsk_ca_ops->init(sk);
if (tcp_ca_needs_ecn(sk))
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index beb4294e9fda..c612daad9e92 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -121,8 +121,10 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
if (udpfrag) {
int err = ip6_find_1stfragopt(skb, &prevhdr);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb_list(segs);
return ERR_PTR(err);
+ }
fptr = (struct frag_hdr *)((u8 *)ipv6h + err);
fptr->frag_off = htons(offset);
if (skb->next)
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index 1737fc0f2988..4c753f4a3712 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -50,7 +50,7 @@ static struct inet_protosw pingv6_protosw = {
.type = SOCK_DGRAM,
.protocol = IPPROTO_ICMPV6,
.prot = &pingv6_prot,
- .ops = &inet6_dgram_ops,
+ .ops = &inet6_sockraw_ops,
.flags = INET_PROTOSW_REUSE,
};
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index d13ed145e93a..0ef8e114c8ab 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1304,7 +1304,7 @@ void raw6_proc_exit(void)
#endif /* CONFIG_PROC_FS */
/* Same as inet6_dgram_ops, sans udp_poll. */
-static const struct proto_ops inet6_sockraw_ops = {
+const struct proto_ops inet6_sockraw_ops = {
.family = PF_INET6,
.owner = THIS_MODULE,
.release = inet6_release,
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
index 0e015906f9ca..07d36573f50b 100644
--- a/net/ipv6/xfrm6_mode_ro.c
+++ b/net/ipv6/xfrm6_mode_ro.c
@@ -47,6 +47,8 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
iph = ipv6_hdr(skb);
hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
+ if (hdr_len < 0)
+ return hdr_len;
skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data);
skb_set_network_header(skb, -x->props.header_len);
skb->transport_header = skb->network_header + hdr_len;
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c
index 4e344105b3fd..1d3bbe6e1183 100644
--- a/net/ipv6/xfrm6_mode_transport.c
+++ b/net/ipv6/xfrm6_mode_transport.c
@@ -28,6 +28,8 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
iph = ipv6_hdr(skb);
hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
+ if (hdr_len < 0)
+ return hdr_len;
skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data);
skb_set_network_header(skb, -x->props.header_len);
skb->transport_header = skb->network_header + hdr_len;
diff --git a/security/keys/key.c b/security/keys/key.c
index 534808915371..09c10b181881 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -934,12 +934,11 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
/* the key must be writable */
ret = key_permission(key_ref, KEY_NEED_WRITE);
if (ret < 0)
- goto error;
+ return ret;
/* attempt to update it if supported */
- ret = -EOPNOTSUPP;
if (!key->type->update)
- goto error;
+ return -EOPNOTSUPP;
memset(&prep, 0, sizeof(prep));
prep.data = payload;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 442e350c209d..671709d8610d 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -97,7 +97,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
/* pull the payload in if one was supplied */
payload = NULL;
- if (_payload) {
+ if (plen) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
if (!payload) {
@@ -327,7 +327,7 @@ long keyctl_update_key(key_serial_t id,
/* pull the payload in if one was supplied */
payload = NULL;
- if (_payload) {
+ if (plen) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload)
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 30b28e80c6e6..f0675acecc93 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1625,6 +1625,7 @@ static int snd_timer_user_tselect(struct file *file,
if (err < 0)
goto __err;
+ tu->qhead = tu->qtail = tu->qused = 0;
kfree(tu->queue);
tu->queue = NULL;
kfree(tu->tqueue);
@@ -1962,6 +1963,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
tu = file->private_data;
unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read);
+ mutex_lock(&tu->ioctl_lock);
spin_lock_irq(&tu->qlock);
while ((long)count - result >= unit) {
while (!tu->qused) {
@@ -1977,7 +1979,9 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
add_wait_queue(&tu->qchange_sleep, &wait);
spin_unlock_irq(&tu->qlock);
+ mutex_unlock(&tu->ioctl_lock);
schedule();
+ mutex_lock(&tu->ioctl_lock);
spin_lock_irq(&tu->qlock);
remove_wait_queue(&tu->qchange_sleep, &wait);
@@ -1997,7 +2001,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
tu->qused--;
spin_unlock_irq(&tu->qlock);
- mutex_lock(&tu->ioctl_lock);
if (tu->tread) {
if (copy_to_user(buffer, &tu->tqueue[qhead],
sizeof(struct snd_timer_tread)))
@@ -2007,7 +2010,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
sizeof(struct snd_timer_read)))
err = -EFAULT;
}
- mutex_unlock(&tu->ioctl_lock);
spin_lock_irq(&tu->qlock);
if (err < 0)
@@ -2017,6 +2019,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
}
_error:
spin_unlock_irq(&tu->qlock);
+ mutex_unlock(&tu->ioctl_lock);
return result > 0 ? result : err;
}
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 61dd478b97e4..28aaf2172221 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1999,13 +1999,11 @@ static struct cal_block_data *adm_find_cal_by_path(int cal_index, int path)
if (cal_index == ADM_AUDPROC_CAL) {
audproc_cal_info = cal_block->cal_info;
- if ((audproc_cal_info->path == path) &&
- (cal_block->cal_data.size > 0))
+ if (audproc_cal_info->path == path)
return cal_block;
} else if (cal_index == ADM_AUDVOL_CAL) {
audvol_cal_info = cal_block->cal_info;
- if ((audvol_cal_info->path == path) &&
- (cal_block->cal_data.size > 0))
+ if (audvol_cal_info->path == path)
return cal_block;
}
}
@@ -2032,14 +2030,12 @@ static struct cal_block_data *adm_find_cal_by_app_type(int cal_index, int path,
if (cal_index == ADM_AUDPROC_CAL) {
audproc_cal_info = cal_block->cal_info;
if ((audproc_cal_info->path == path) &&
- (audproc_cal_info->app_type == app_type) &&
- (cal_block->cal_data.size > 0))
+ (audproc_cal_info->app_type == app_type))
return cal_block;
} else if (cal_index == ADM_AUDVOL_CAL) {
audvol_cal_info = cal_block->cal_info;
if ((audvol_cal_info->path == path) &&
- (audvol_cal_info->app_type == app_type) &&
- (cal_block->cal_data.size > 0))
+ (audvol_cal_info->app_type == app_type))
return cal_block;
}
}
@@ -2070,15 +2066,13 @@ static struct cal_block_data *adm_find_cal(int cal_index, int path,
if ((audproc_cal_info->path == path) &&
(audproc_cal_info->app_type == app_type) &&
(audproc_cal_info->acdb_id == acdb_id) &&
- (audproc_cal_info->sample_rate == sample_rate) &&
- (cal_block->cal_data.size > 0))
+ (audproc_cal_info->sample_rate == sample_rate))
return cal_block;
} else if (cal_index == ADM_AUDVOL_CAL) {
audvol_cal_info = cal_block->cal_info;
if ((audvol_cal_info->path == path) &&
(audvol_cal_info->app_type == app_type) &&
- (audvol_cal_info->acdb_id == acdb_id) &&
- (cal_block->cal_data.size > 0))
+ (audvol_cal_info->acdb_id == acdb_id))
return cal_block;
}
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index cac2d4975a15..e63b4346e82e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1792,6 +1792,9 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
for (i = 0; i < card->num_aux_devs; i++)
soc_remove_aux_dev(card, i);
+ /* free the ALSA card at first; this syncs with pending operations */
+ snd_card_free(card->snd_card);
+
/* remove and free each DAI */
soc_remove_dai_links(card);
@@ -1803,9 +1806,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
snd_soc_dapm_free(&card->dapm);
- snd_card_free(card->snd_card);
return 0;
-
}
/* removes a socdev */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 70dfdd22102e..d5cc315a5eb4 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1012,6 +1012,17 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
cval->res = 384;
}
break;
+
+ case USB_ID(0x1130, 0x1620): /* Logitech Speakers S150 */
+ /* This audio device has 2 channels and it explicitly requires the
+ * host to send SET_CUR command on the volume control of both the
+ * channels. 7936 = 0x1F00 is the default value.
+ */
+ if (cval->channels == 2)
+ snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
+ (cval->control << 8) | 2, 7936);
+ break;
+
}
}