OSDN Git Service

Merge "msm: ipa: Add a support to retry uC send command"
authorLinux Build Service Account <lnxbuild@quicinc.com>
Fri, 5 May 2017 00:44:30 +0000 (17:44 -0700)
committerGerrit - the friendly Code Review server <code-review@localhost>
Fri, 5 May 2017 00:44:30 +0000 (17:44 -0700)
480 files changed:
Documentation/devicetree/bindings/arm/msm/clock-cpu-8996.txt
Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
Documentation/devicetree/bindings/arm/msm/msm.txt
Documentation/devicetree/bindings/cache/msm_cache_erp64.txt [new file with mode: 0644]
Documentation/devicetree/bindings/cache/msm_m4m_erp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
Documentation/devicetree/bindings/net/neutrino_avb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pil/subsys-pil-tz.txt
Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt [new file with mode: 0644]
Documentation/sysctl/fs.txt
Makefile
arch/arm/boot/Makefile
arch/arm/boot/dts/qcom/Makefile
arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8096pro-v1.1.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/apq8098-cdp.dts
arch/arm/boot/dts/qcom/apq8098-mtp.dts
arch/arm/boot/dts/qcom/apq8098-v2-cdp.dts
arch/arm/boot/dts/qcom/apq8098-v2-mtp.dts
arch/arm/boot/dts/qcom/apq8098-v2-qrd-skuk-hdk.dts
arch/arm/boot/dts/qcom/apq8098-v2-qrd.dts
arch/arm/boot/dts/qcom/apq8098-v2.1-cdp.dts
arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts
arch/arm/boot/dts/qcom/apq8098-v2.1-mtp.dts
arch/arm/boot/dts/qcom/apq8098-v2.1-qrd.dts
arch/arm/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi
arch/arm/boot/dts/qcom/external-mdm9640.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi
arch/arm/boot/dts/qcom/msm8996-pm.dtsi
arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi
arch/arm/boot/dts/qcom/msm8996-sde.dtsi
arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts
arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp-lite.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996.dtsi
arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8996pro.dtsi
arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts
arch/arm/boot/dts/qcom/msm8998-cdp.dts
arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts
arch/arm/boot/dts/qcom/msm8998-mtp.dts
arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dts
arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dts
arch/arm/boot/dts/qcom/msm8998-qrd.dts
arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts
arch/arm/boot/dts/qcom/msm8998-v2-cdp.dts
arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts
arch/arm/boot/dts/qcom/msm8998-v2-mtp.dts
arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-evt3.dts
arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts
arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk.dts
arch/arm/boot/dts/qcom/msm8998-v2-qrd-vr1.dts
arch/arm/boot/dts/qcom/msm8998-v2-qrd.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-cdp.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-cdp.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-mtp.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-sdm660-qrd.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-4k-display.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-mtp.dts
arch/arm/boot/dts/qcom/msm8998-v2.1-qrd.dts
arch/arm/boot/dts/qcom/msm8998.dtsi
arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
arch/arm/configs/sdm660-perf_defconfig
arch/arm/configs/sdm660_defconfig
arch/arm/include/asm/dma-contiguous.h
arch/arm/kvm/mmu.c
arch/arm64/Kconfig
arch/arm64/configs/msm-auto-perf_defconfig [new file with mode: 0644]
arch/arm64/configs/msm-auto_defconfig [new file with mode: 0644]
arch/arm64/configs/msm-perf_defconfig
arch/arm64/configs/msm_defconfig
arch/arm64/configs/msmcortex-perf_defconfig
arch/arm64/configs/msmcortex_defconfig
arch/arm64/configs/msmcortex_mediabox_defconfig
arch/arm64/configs/sdm660-perf_defconfig
arch/arm64/configs/sdm660_defconfig
arch/arm64/include/asm/app_api.h [new file with mode: 0644]
arch/arm64/include/asm/dma-contiguous.h
arch/arm64/include/asm/dma-iommu.h
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/app_api.c [new file with mode: 0644]
arch/arm64/kernel/app_setting.c [new file with mode: 0644]
arch/arm64/kernel/entry-fpsimd.S
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/sleep.S
arch/metag/include/asm/uaccess.h
arch/metag/lib/usercopy.c
arch/mips/Kconfig
arch/mips/include/asm/irq.h
arch/mips/include/asm/spinlock.h
arch/mips/include/asm/stackframe.h
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/genex.S
arch/mips/kernel/irq.c
arch/mips/kernel/process.c
arch/mips/lantiq/xway/sysctrl.c
arch/mips/mm/tlbex.c
arch/mips/ralink/rt3883.c
arch/nios2/kernel/prom.c
arch/nios2/kernel/setup.c
arch/powerpc/kernel/align.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/setup_64.c
arch/powerpc/mm/hash_native_64.c
arch/s390/boot/compressed/misc.c
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/uaccess.h
arch/x86/entry/vdso/vdso32-setup.c
arch/x86/include/asm/elf.h
arch/x86/include/asm/pmem.h
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c
arch/x86/kvm/vmx.c
arch/x86/mm/init.c
arch/x86/xen/setup.c
block/bio.c
block/blk-core.c
block/blk-mq.c
block/genhd.c
crypto/ahash.c
drivers/acpi/Makefile
drivers/acpi/acpi_platform.c
drivers/acpi/nfit.c
drivers/acpi/power.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btfm_slim.h
drivers/bluetooth/btfm_slim_wcn3990.c
drivers/char/Kconfig
drivers/char/adsprpc.c
drivers/char/diag/diagfwd_glink.c
drivers/char/diag/diagfwd_glink.h
drivers/char/mem.c
drivers/char/virtio_console.c
drivers/clk/clk.c
drivers/clk/msm/clock-cpu-8996.c
drivers/clk/msm/clock-gcc-8996.c
drivers/crypto/caam/ctrl.c
drivers/esoc/esoc-mdm-4x.c
drivers/esoc/esoc-mdm-drv.c
drivers/esoc/esoc-mdm-pon.c
drivers/esoc/esoc-mdm.h
drivers/esoc/esoc.h
drivers/esoc/esoc_bus.c
drivers/esoc/esoc_dev.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/a4xx_gpu.c
drivers/gpu/drm/msm/adreno/a5xx_gpu.c
drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/dba_bridge.c [new file with mode: 0644]
drivers/gpu/drm/msm/dba_bridge.h [new file with mode: 0644]
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c
drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
drivers/gpu/drm/msm/dsi-staging/dsi_display.c
drivers/gpu/drm/msm/dsi-staging/dsi_display.h
drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gem_vma.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/msm/msm_mmu.h
drivers/gpu/drm/msm/msm_prop.c
drivers/gpu/drm/msm/msm_prop.h
drivers/gpu/drm/msm/msm_smmu.c
drivers/gpu/drm/msm/msm_snapshot.h
drivers/gpu/drm/msm/msm_snapshot_api.h
drivers/gpu/drm/msm/sde/sde_backlight.c
drivers/gpu/drm/msm/sde/sde_connector.c
drivers/gpu/drm/msm/sde/sde_formats.c
drivers/gpu/drm/msm/sde/sde_kms.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/ttm/ttm_object.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/gpu/msm/kgsl_sharedmem.c
drivers/hv/channel.c
drivers/hv/connection.c
drivers/hv/hv.c
drivers/hv/hv_balloon.c
drivers/iio/gyro/bmg160_core.c
drivers/input/joystick/xpad.c
drivers/input/misc/hbtp_input.c
drivers/input/mouse/elantech.c
drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
drivers/iommu/Kconfig
drivers/iommu/arm-smmu.c
drivers/iommu/io-pgtable-arm.c
drivers/iommu/io-pgtable.h
drivers/iommu/iommu-debug.c
drivers/iommu/iommu.c
drivers/irqchip/irq-imx-gpcv2.c
drivers/md/Makefile
drivers/md/dm.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
drivers/media/platform/msm/camera_v2/msm.c
drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
drivers/media/platform/msm/sde/rotator/sde_rotator_r1_ctl.c
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
drivers/media/usb/dvb-usb/dvb-usb-firmware.c
drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
drivers/misc/uid_sys_stats.c
drivers/mmc/card/queue.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/host/cmdq_hci.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mtd/bcm47xxpart.c
drivers/mtd/ubi/upd.c
drivers/net/can/spi/rh850.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmveth.h
drivers/net/ethernet/mellanox/mlx4/cq.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/usb/catc.c
drivers/net/usb/pegasus.c
drivers/net/usb/rtl8150.c
drivers/net/wireless/ath/ath10k/qmi.c
drivers/net/wireless/ath/ath10k/snoc.c
drivers/net/wireless/ath/ath9k/common-spectral.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/nvdimm/bus.c
drivers/pci/host/pci-msm.c
drivers/platform/msm/gpio-usbdetect.c
drivers/platform/msm/ipa/ipa_v2/ipa.c
drivers/platform/msm/ipa/ipa_v3/ipa.c
drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
drivers/platform/x86/acer-wmi.c
drivers/power/power_supply_sysfs.c
drivers/power/reset/at91-poweroff.c
drivers/power/reset/msm-poweroff.c
drivers/power/supply/qcom/battery.c
drivers/power/supply/qcom/battery.h [new file with mode: 0644]
drivers/power/supply/qcom/qpnp-smb2.c
drivers/power/supply/qcom/smb-lib.c
drivers/power/supply/qcom/smb-lib.h
drivers/power/supply/qcom/smb-reg.h
drivers/power/supply/qcom/smb138x-charger.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/onsemi-ncp6335d.c [new file with mode: 0644]
drivers/rtc/rtc-s35390a.c
drivers/rtc/rtc-tegra.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/boot_marker.c [new file with mode: 0644]
drivers/soc/qcom/boot_stats.c
drivers/soc/qcom/cache_m4m_erp64.c [new file with mode: 0644]
drivers/soc/qcom/icnss.c
drivers/soc/qcom/ipc_router_mhi_xprt.c
drivers/soc/qcom/memory_dump_v2.c
drivers/soc/qcom/msm_minidump.c
drivers/soc/qcom/perf_event_kryo.c
drivers/soc/qcom/peripheral-loader.c
drivers/soc/qcom/qbt1000.c
drivers/soc/qcom/qdsp6v2/apr.c
drivers/soc/qcom/scm-boot.c
drivers/soc/qcom/service-notifier.c
drivers/soc/qcom/socinfo.c
drivers/soc/qcom/subsystem_restart.c
drivers/staging/android/ion/ion.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_util.c
drivers/tty/nozomi.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/msm_serial.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/dwc3/dwc3-msm.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/ks_bridge.c [new file with mode: 0644]
drivers/usb/pd/policy_engine.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/video/fbdev/Makefile
drivers/video/fbdev/msm/mdss_dsi_phy.h
drivers/video/fbdev/msm/mdss_dsi_phy_v3.c
drivers/video/fbdev/msm/mdss_mdp_layer.c
drivers/video/fbdev/msm/mdss_mdp_wfd.c
drivers/video/fbdev/msm/mdss_rotator.c
drivers/video/fbdev/msm/msm_dba/adv7533.c
drivers/video/fbdev/msm/msm_dba/msm_dba_helpers.c
drivers/video/fbdev/msm/msm_mdss_io_8974.c
drivers/video/fbdev/xen-fbfront.c
fs/Makefile
fs/cifs/cifsglob.h
fs/cifs/file.c
fs/cifs/smb1ops.c
fs/cifs/smb2pdu.c
fs/ecryptfs/main.c
fs/ext2/ext2.h
fs/ext2/super.c
fs/ext2/xattr.c
fs/ext2/xattr.h
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/f2fs/super.c
fs/gfs2/dir.c
fs/mbcache.c
fs/mbcache2.c [new file with mode: 0644]
fs/mount.h
fs/namespace.c
fs/pnode.c
fs/pnode.h
fs/proc/task_mmu.c
fs/sdcardfs/dentry.c
fs/sdcardfs/derived_perm.c
fs/sdcardfs/file.c
fs/sdcardfs/lookup.c
fs/sdcardfs/mmap.c
fs/sdcardfs/multiuser.h
fs/sysfs/file.c
include/crypto/internal/hash.h
include/drm/ttm/ttm_object.h
include/linux/cgroup.h
include/linux/ieee80211.h
include/linux/iommu.h
include/linux/kasan.h
include/linux/kvm_host.h
include/linux/mbcache2.h [new file with mode: 0644]
include/linux/mm_types.h
include/linux/mount.h
include/linux/power_supply.h
include/linux/regulator/onsemi-ncp6335d.h [new file with mode: 0644]
include/linux/sched.h
include/net/cfg80211.h
include/soc/qcom/boot_stats.h
include/soc/qcom/minidump.h
include/soc/qcom/profiler.h
include/soc/qcom/socinfo.h
include/soc/qcom/subsystem_restart.h
include/sound/msm-dts-eagle.h [deleted file]
include/sound/q6adm-v2.h
include/trace/events/clk.h
include/uapi/drm/msm_drm.h
include/uapi/linux/esoc_ctrl.h
include/uapi/linux/nl80211.h
include/uapi/media/msmb_ispif.h
kernel/cgroup.c
kernel/events/core.c
kernel/kthread.c
kernel/padata.c
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/suspend.c
kernel/power/user.c
kernel/ptrace.c
kernel/sched/core.c
kernel/sysctl.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
mm/hugetlb.c
mm/kasan/kasan.c
mm/mempolicy.c
mm/mmap.c
net/ceph/messenger.c
net/ipv4/ping.c
net/ipv4/route.c
net/ipv6/route.c
net/mac80211/rx.c
net/packet/af_packet.c
net/sctp/socket.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/core.c
net/tipc/core.h
net/tipc/name_distr.c
net/tipc/node.c
net/tipc/socket.c
net/tipc/udp_media.c
net/vmw_vsock/vmci_transport.c
net/wireless/core.h
net/wireless/db.txt
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/sme.c
net/wireless/util.c
scripts/checkpatch.pl
security/keys/gc.c
security/keys/keyctl.c
security/keys/process_keys.c
sound/core/seq/seq_fifo.c
sound/pci/hda/patch_realtek.c
sound/soc/atmel/atmel-classd.c
sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
sound/soc/msm/qdsp6v2/Makefile
sound/soc/msm/qdsp6v2/audio_cal_utils.c
sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
sound/soc/msm/qdsp6v2/msm-dts-eagle.c [deleted file]
sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c
sound/soc/msm/qdsp6v2/msm-lsm-client.c
sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c
sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
sound/soc/msm/qdsp6v2/q6adm.c
sound/soc/msm/qdsp6v2/q6asm.c
sound/soc/msm/qdsp6v2/q6core.c
tools/hv/hv_kvp_daemon.c
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

index f3c6cc7..bb74c16 100644 (file)
@@ -8,6 +8,7 @@ PLL FMAXes etc.
 Required properties:
 - compatible:          Must be either "qcom,cpu-clock-8996" or
                        "qcom,cpu-clock-8996-v3" or "qcom,cpu-clock-8996-pro"
+                       or "qcom,cpu-clock-8996-auto"
 - reg:                 Pairs of physical base addresses and region sizes of
                        memory mapped registers.
 - reg-names:           Names of the bases for the above registers. Expected
@@ -39,6 +40,11 @@ Required properties:
                        clock for the CBF.
 - cbf-dev:             The CBF cache device to which the OPP table for the
                        CBF clock domain will be added.
+
+Optional properties:
+- qcom,pwrcl-early-boot-freq:  Power cluster early boot up frequency in HZ.
+- qcom,perfcl-early-boot-freq: Perf cluster early boot up frequency in HZ.
+
 Example:
        clock_cpu: qcom,cpu-clock-8996@ {
                compatible = "qcom,cpu-clock-8996";
index a6537eb..7d5e8a1 100644 (file)
@@ -6,8 +6,8 @@ to be reset.
 
 Required Properties:
 - compatible:  The bus devices need to be compatible with
-               "qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom, ext-mdm9x45",
-               "qcom,ext-mdm9x55".
+               "qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom,ext-mdm9x45",
+               "qcom,ext-mdm9x55", "qcom,ext-apq8096".
 
 Required named gpio properties:
 - qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor
@@ -110,6 +110,10 @@ Optional driver parameters:
                           on behalf of the subsystem driver.
 - qcom,mdm-link-info: a string indicating additional info about the physical link.
                        For example: "devID_domain.bus.slot" in case of PCIe.
+- qcom,mdm-auto-boot: Boolean. To indicate this instance of esoc boots independently.
+- qcom,mdm-statusline-not-a-powersource: Boolean. If set, status line to esoc device is not a
+               power source.
+- qcom,mdm-userspace-handle-shutdown: Boolean. If set, userspace handles shutdown requests.
 
 Example:
        mdm0: qcom,mdm0 {
index 781f058..d442cf0 100644 (file)
@@ -186,6 +186,7 @@ compatible = "qcom,apq8094-fluid"
 compatible = "qcom,apq8094-liquid"
 compatible = "qcom,apq8094-mtp"
 compatible = "qcom,apq8094-dragonboard"
+compatible = "qcom,apq8096-adp"
 compatible = "qcom,apq8096-cdp"
 compatible = "qcom,apq8096-mtp"
 compatible = "qcom,apq8096-dragonboard"
diff --git a/Documentation/devicetree/bindings/cache/msm_cache_erp64.txt b/Documentation/devicetree/bindings/cache/msm_cache_erp64.txt
new file mode 100644 (file)
index 0000000..5dfb6d6
--- /dev/null
@@ -0,0 +1,26 @@
+* MSM 64bit L0, L1, L2 and L3 cache error reporting driver
+
+Required properties:
+- compatible: Should be "qcom,kryo_cache_erp64"
+- reg: I/O address L3 hardware block.
+- interrupts: Should contain the L0/L1, L2 and L3 cache error interrupt number.
+- interrupt-names: Should contain the interrupt names "l1_irq", "l2_irq_info_0",
+                  "l2_irq_info_1", "l2_irq_err_0", "l2_irq_err_1", "l3_irq".
+
+Example:
+       qcom,cache_erp64@6500000 {
+               compatible = "qcom,kryo_cache_erp64";
+               reg = <0x6500000 0x4000>;
+               /*
+                * PPI 0  for L0/L1
+                * SPI 1  for Cluster 1 L2 Info
+                * SPI 9  for Cluster 2 L2 Info
+                * SPI 2  for Cluster 1 L2 Error
+                * SPI 10 for Cluster 2 L2 Error
+                * SPI 17 for L3 error
+                */
+               interrupts = <1 0 0>, <0 1 0>, <0 9 0>, <0 2 0>, <0 10 0>,
+                            <0 17 0>;
+               interrupt-names = "l1_irq", "l2_irq_info_0", "l2_irq_info_1",
+                                 "l2_irq_err_0", "l2_irq_err_1", "l3_irq";
+       };
diff --git a/Documentation/devicetree/bindings/cache/msm_m4m_erp.txt b/Documentation/devicetree/bindings/cache/msm_m4m_erp.txt
new file mode 100644 (file)
index 0000000..5526f11
--- /dev/null
@@ -0,0 +1,15 @@
+* MSM M4M error reporting driver
+
+Required properties:
+- compatible: Should be "qcom,m4m_erp".
+- reg: I/O address M4M hardware block.
+- interrupts: Should contain the M4M error interrupt number.
+- interrupt-names: Should contain the interrupt names "m4m_irq".
+
+Example:
+       qcom,m4m_erp64@9A40000 {
+               compatible = "qcom,m4m_erp";
+               reg = <0x9A40000 0x40000>;
+               interrupts = <0 22 0>;
+               interrupt-names = "m4m_irq";
+       };
index ce5ee56..1f8458c 100644 (file)
@@ -563,6 +563,7 @@ Optional properites:
                                        to a non-DSI interface.
 - qcom,bridge-name:                    A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name
                                        is required if qcom,dba-panel is defined for the panel.
+- qcom,hdmi-mode:                      Indicates where current panel is HDMI mode, otherwise, it will be DVI mode.
 - qcom,adjust-timer-wakeup-ms:         An integer value to indicate the timer delay(in ms) to accommodate
                                        s/w delay while configuring the event timer wakeup logic.
 
diff --git a/Documentation/devicetree/bindings/net/neutrino_avb.txt b/Documentation/devicetree/bindings/net/neutrino_avb.txt
new file mode 100644 (file)
index 0000000..46c6a52
--- /dev/null
@@ -0,0 +1,28 @@
+* Neutrino Ethernet *
+This driver implements Ethernet driver for Neutrino ethernet controller
+Required properties:
+  - compatible: Should be "qcom,ntn_avb"
+  - ntn-rst-gpio: Neutrino reset GPIO
+  - vdd-ntn-hsic-supply: neutrino HSIC power supply
+  - vdd-ntn-pci-supply: PCIe core power supply
+  - vdd-ntn-io-supply:  Neutrino IO power supply
+  - vdd-ntn-phy-supply: Ethernet Phy power supply
+  - vdd-ntn-core-supply:  Neutrino core power supply
+  - pinctrl-names: should contain GPIO details
+  - pinctrl-0: Neutrino reset GPIO [this is from MSM]
+  - ntn-rst-delay-msec: dealy (msec) required after PCIe reset for stabilization
+  - ntn-rc-num: PCIe root complex number on which Neutrino is connected
+Example:
+       qcom,ntn_avb {
+               compatible = "qcom,ntn_avb";
+               ntn-rst-gpio = <&pm8994_gpios 13 0>;
+               vdd-ntn-hsic-supply = <&pm8994_l25>;
+               vdd-ntn-pci-supply = <&pm8994_s4>;
+               vdd-ntn-io-supply = <&pm8994_s4>;
+               vdd-ntn-phy-supply = <&pm8994_l9>;
+               vdd-ntn-core-supply = <&pm8994_l19>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ntn_default>;
+               qcom,ntn-rst-delay-msec = <100>;
+               qcom,ntn-rc-num = <1>;
+       };
index d7edafc..4a69e03 100644 (file)
@@ -67,6 +67,7 @@ Optional properties:
 - qcom,complete-ramdump: Boolean. If set, complete ramdump i.e. region between start address of
                        first segment to end address of last segment will be collected without
                        leaving any hole in between.
+- qcom,ignore-ssr-failure: Boolean. If set, SSR failures are not considered fatal.
 
 Example:
        qcom,venus@fdce0000 {
index 5529e30..92ef23c 100644 (file)
@@ -22,8 +22,7 @@ Charger specific properties:
   Definition: String which indicates the charging mode. Can be one of the
              following:
               Standalone/Parallel Master       - "qcom,smb138x-charger"
-             smb138x Parallel Slave            - "qcom,smb138x-parallel-slave"
-             smb1355 Parallel Slave            - "qcom,smb1355-parallel-slave",
+             Parallel Slave                    - "qcom,smb138x-parallel-slave"
 
 - qcom,pmic-revid
   Usage:      required
@@ -36,8 +35,7 @@ Charger specific properties:
   Usage:      optional
   Value type: <u32>
   Definition: Specifies parallel charging mode. If not specified, MID-MID
-             option is selected by default. Note that smb1355 can only
-             run in MID-MID configuration.
+             option is selected by default.
 
 - qcom,suspend-input
   Usage:      optional
@@ -127,7 +125,7 @@ Example
 =======
 
 smb138x_charger: qcom,smb138x-charger {
-       compatible = "qcom,smb138x-charger";
+       compatible = "qcom,qpnp-smb138x-charger";
        #address-cells = <1>;
        #size-cells = <1>;
 
diff --git a/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt b/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt
new file mode 100644 (file)
index 0000000..7d492f5
--- /dev/null
@@ -0,0 +1,72 @@
+ON Semiconductor NCP6335d regulator
+
+NCP6335d is able to deliver up to 5.0 A, with programmable output voltage from
+0.6 V to 1.87 V in 10mV steps, with synchronous rectification and automatic PWM/
+PFM transitions, enable pins and power good/fail signaling.
+
+The NCP6335d interface is via I2C bus.
+
+Required Properties:
+- compatible:                  Must be "onnn,ncp6335d-regulator".
+- reg:                         The device 8-bit I2C address.
+- regulator-min-microvolt:     Minimum voltage in microvolts supported by this
+                               regulator.
+- regulator-max-microvolt:     Maximum voltage in microvolts supported by this
+                               regulator.
+- onnn,min-setpoint:           Minimum setpoint voltage in microvolts supported
+                               by this regulator.
+- onnn,step-size:              The step size of the regulator, in uV.
+- onnn,min-slew-ns:            Minimum time in ns needed to change voltage by
+                               one step size. This value corresponds to DVS
+                               mode bit of 00b in command register.
+- onnn,max-slew-ns:            Maximum time in ns needed to change voltage by
+                               one step size. This value corresponds to DVS
+                               mode bit of 11b in command register.
+- onnn,vsel:                   Working vsel register. Supported value are 0
+                               or 1.
+- onnn,slew-ns:                        Time in ns needed to change voltage by one step
+                               size. Supported value are 333, 666, 1333, 2666.
+
+Optional Properties:
+- onnn,discharge-enable:       Present: discharge enabled.
+                               Not Present: discharge disabled.
+- onnn,restore-reg:            Present: Restore vsel register from backup register.
+                               Not Present: No restore.
+- onnn,vsel-gpio:              Present: GPIO connects to the VSEL pin and set the
+                               VSEL pin according to device tree flag.
+                               Not Present: No GPIO is connected to vsel pin.
+- pinctrl-names:               The state name of the VSEL pin configuration.
+                               Only support: "default"
+- pinctrl-0:                   The phandles of the pin configuration node in
+                               pinctrl for VSEL pin.
+                               For details of pinctrl properties, please refer to:
+                               "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+- onnn,sleep-enable:           Present: Forced in sleep mode when EN and VSEL
+                               pins are low.
+                               Not Present: Low quiescent current mode when EN and VSEL
+                               pins are low.
+- onnn,mode:                   A string which specifies the initial mode to use for the regulator.
+                               Supported values are "pwm" and "auto". PWM mode is more
+                               robust, but draws more current than auto mode. If this propery
+                               is not specified, then the regulator will be in the hardware default mode.
+
+Example:
+       i2c_0 {
+               ncp6335d-regulator@1c {
+                       compatible = "onnn,ncp6335d-regulator";
+                       reg = <0x1c>;
+                       onnn,vsel = <0>;
+                       onnn,slew-rate-ns = <2666>;
+                       onnn,discharge-enable;
+                       onnn,step-size = <10000>;
+                       onnn,min-slew-ns = <333>;
+                       onnn,max-slew-ns = <2666>;
+                       pintrl-names = "default";
+                       pinctrl-0 = <&ext_buck_vsel_default>;
+
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1350000>;
+                       onnn,min-setpoint = <600000>;
+                       onnn,vsel-gpio = <&msmgpio 2 1>;
+               };
+       };
index 302b5ed..35e17f7 100644 (file)
@@ -265,6 +265,13 @@ aio-nr can grow to.
 
 ==============================================================
 
+mount-max:
+
+This denotes the maximum number of mounts that may exist
+in a mount namespace.
+
+==============================================================
+
 
 2. /proc/sys/fs/binfmt_misc
 ----------------------------------------------------------
index 759c164..933d159 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 4
-SUBLEVEL = 59
+SUBLEVEL = 65
 EXTRAVERSION =
 NAME = Blurry Fish Butt
 
index 8849c2d..a527829 100644 (file)
@@ -69,7 +69,7 @@ $(obj)/zImage:        $(obj)/compressed/vmlinux FORCE
 
 $(obj)/zImage-dtb:     $(obj)/zImage $(DTB_OBJS) FORCE
        $(call if_changed,cat)
-       @echo '  Kernel: $@ is ready'
+       @$(kecho) '  Kernel: $@ is ready'
 
 endif
 
index 27f79c2..8e7f26b 100644 (file)
@@ -10,6 +10,7 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
        msm8996-v2-liquid.dtb \
        msm8996-v2-dtp.dtb \
        msm8996-v3-auto-cdp.dtb \
+       msm8996-v3-auto-adp.dtb \
        msm8996-v3-pmi8994-cdp.dtb \
        msm8996-v3-pmi8994-mtp.dtb \
        msm8996-v3-pmi8994-pmk8001-cdp.dtb \
@@ -27,6 +28,10 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
        msm8996-v3-dtp.dtb \
        msm8996-v3-pm8004-mmxf-adp.dtb \
        msm8996-v3-pm8004-agave-adp.dtb \
+       msm8996-v3-pm8004-agave-adp-lite.dtb \
+       msm8996pro-auto-adp.dtb \
+       msm8996pro-auto-adp-lite.dtb \
+       msm8996pro-auto-cdp.dtb \
        msm8996pro-pmi8994-cdp.dtb \
        msm8996pro-pmi8994-mtp.dtb \
        msm8996pro-pmi8994-pmk8001-cdp.dtb \
@@ -39,6 +44,7 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
        msm8996pro-pmi8996-mtp.dtb \
        msm8996pro-pmi8996-pmk8001-cdp.dtb \
        msm8996pro-pmi8996-pmk8001-mtp.dtb \
+       msm8996pro-v1.1-auto-cdp.dtb \
        msm8996pro-v1.1-pmi8994-cdp.dtb \
        msm8996pro-v1.1-pmi8994-mtp.dtb \
        msm8996pro-v1.1-pmi8994-pmk8001-cdp.dtb \
@@ -51,7 +57,11 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
        msm8996pro-v1.1-pmi8996-mtp.dtb \
        msm8996pro-v1.1-pmi8996-pmk8001-cdp.dtb \
        msm8996pro-v1.1-pmi8996-pmk8001-mtp.dtb \
+       apq8096pro-auto-cdp.dtb \
+       apq8096pro-v1.1-auto-adp.dtb \
+       apq8096pro-v1.1-auto-adp-lite.dtb \
        apq8096pro-liquid.dtb \
+       apq8096pro-v1.1-auto-cdp.dtb \
        msm8996-v3.0-pmi8994-cdp.dtb \
        msm8996-v3.0-pmi8994-mtp.dtb \
        msm8996-v3.0-pmi8994-pm8004-cdp.dtb \
@@ -82,6 +92,8 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
        apq8096-v3-dragonboard.dtb \
        apq8096-v3-sbc.dtb \
        apq8096-v3-auto-dragonboard.dtb \
+       apq8096-v3-auto-adp.dtb \
+       apq8096-v3-auto-cdp.dtb \
        apq8096-v3.0-pmi8994-cdp.dtb \
        apq8096-v3.0-pmi8994-mtp.dtb \
        apq8096-v3.0-pmi8994-pm8004-cdp.dtb \
index 57a0467..549bb9c 100644 (file)
 };
 
 &soc {
+       qcom,ntn_avb {
+               compatible = "qcom,ntn_avb";
+
+               ntn-rst-gpio = <&pm8994_gpios 13 0>;
+
+               vdd-ntn-hsic-supply = <&pm8994_l25>;
+               vdd-ntn-pci-supply = <&pm8994_s4>;
+               vdd-ntn-io-supply = <&pm8994_s4>;
+
+               qcom,ntn-rst-delay-msec = <100>;
+               qcom,ntn-rc-num = <1>;
+       };
+
        qcom,cnss {
                wlan-bootstrap-gpio = <&tlmm 46 0>;
                wlan-en-gpio = <&pm8994_gpios 8 0>;
                status = "okay";
        };
 
-       gpio@cc00 { /* GPIO 13 */
-               qcom,mode = <1>;        /* DIGITAL OUT */
-               qcom,vin-sel = <2>;     /* 1.8 */
-               qcom,src-sel = <0>;     /* GPIO */
-               qcom,master-en = <1>;   /* Enable GPIO */
+       gpio@cc00 { /* GPIO 13 - NTN_RST */
+               qcom,mode = <1>; /* DIGITAL OUT */
+               qcom,output-type = <0>; /* CMOS logic */
+               qcom,pull = <5>;
+               qcom,vin-sel = <2>; /* 1.8 */
+               qcom,out-strength = <1>;
+               qcom,src-sel = <0>; /* GPIO */
+               qcom,master-en = <1>; /* Enable GPIO */
                status = "okay";
        };
 
diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts
new file mode 100644 (file)
index 0000000..a91ec5e
--- /dev/null
@@ -0,0 +1,161 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "apq8096-v3.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-agave-adp.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. APQ 8096 v3 AUTO ADP";
+       compatible = "qcom,apq8096-adp", "qcom,apq8096", "qcom,adp";
+       qcom,msm-id = <311 0x30001>;
+       qcom,board-id = <0x02010019 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <122 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&soc {
+       qcom,msm-ssc-sensors {
+               status = "disabled";
+       };
+
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
+
+&slim_msm {
+       status = "disabled";
+};
+
+&pm8994_mpps {
+       mpp@a500 { /* MPP 6 */
+               qcom,mode = <1>;                /* Digital output */
+               qcom,output-type = <0>;         /* CMOS logic */
+               qcom,vin-sel = <2>;             /* S4 1.8V */
+               qcom,src-sel = <0>;             /* Constant */
+               qcom,master-en = <1>;           /* Enable GPIO */
+               status = "okay";
+       };
+};
+
+&hl7509_en_vreg {
+       status = "ok";
+};
+
+&hl7509_vreg {
+       status = "ok";
+};
+
+&sdhc_2 {
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>;
+       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+                       &sdc2_cd_on_sbc>;
+};
+
+&i2c_7 {
+       silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/
+               status = "disabled";
+       };
+};
+
+&gfx_cpr {
+       vdd-supply = <&hl7509_vreg>;
+       qcom,cpr-step-quot-init-min = <20>;
+       qcom,cpr-step-quot-init-max = <26>;
+       qcom,voltage-step = <10000>;
+       /delete-property/ qcom,cpr-enable;
+};
+
+&gfx_vreg {
+       qcom,cpr-voltage-ceiling =
+               <600000  670000  670000  750000  830000
+                910000  960000 1020000>;
+       qcom,cpr-voltage-floor =
+               <600000  600000  600000  600000  600000
+                600000  600000  600000>;
+};
+
+&pm8994_l3 {
+       regulator-min-microvolt = <875000>;
+       regulator-max-microvolt = <875000>;
+       qcom,init-voltage = <875000>;
+};
+
+&pm8994_l11 {
+       regulator-min-microvolt = <850000>;
+       regulator-max-microvolt = <850000>;
+       qcom,init-voltage = <850000>;
+};
+
+&pm8994_l17 {
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       qcom,init-voltage = <1800000>;
+};
+
+&pm8994_l23 {
+       regulator-min-microvolt = <1100000>;
+       regulator-max-microvolt = <1100000>;
+       qcom,init-voltage = <1100000>;
+};
+
+&pm8994_l27 {
+       regulator-min-microvolt = <800000>;
+       regulator-max-microvolt = <800000>;
+       qcom,init-voltage = <800000>;
+};
+
+&pm8994_l29 {
+       regulator-min-microvolt = <2500000>;
+       regulator-max-microvolt = <2500000>;
+       qcom,init-voltage = <2500000>;
+};
+
+&rpm_bus {
+       rpm-regulator-ldoa26 {
+               /delete-node/ pm8994_l26_corner;
+               /delete-node/ pm8994_l26_floor_corner;
+
+               pm8994_l26: regulator-l26 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+                       qcom,init-voltage = <1100000>;
+                       status = "okay";
+               };
+       };
+
+       rpm-regulator-ldoa31 {
+               status = "okay";
+               pm8994_l31: regulator-l31 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+                       qcom,init-voltage = <1100000>;
+                       status = "okay";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts
new file mode 100644 (file)
index 0000000..e59003f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8096-v3.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-auto-cdp.dtsi"
+#include "msm8996v3-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. APQ 8096 v3 AUTO CDP";
+       compatible = "qcom,apq8096-cdp", "qcom,apq8096", "qcom,cdp";
+       qcom,msm-id = <311 0x30001>;
+       qcom,board-id = <0x03010001 0>;
+};
+
+&soc {
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <127 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts
new file mode 100644 (file)
index 0000000..d438bbe
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8096pro.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-auto-cdp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. APQ 8096 pro AUTO CDP";
+       compatible = "qcom,apq8096-cdp", "qcom,apq8096", "qcom,cdp";
+       qcom,msm-id = <316 0x10000>;
+       qcom,board-id = <0x03010001 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <127 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&soc {
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
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
new file mode 100644 (file)
index 0000000..9c4ff9f
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "apq8096pro.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-agave-adp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. APQ 8096pro V1.1 AUTO ADP LITE";
+       compatible = "qcom,apq8096-adp", "qcom,msm8996", "qcom,adp";
+       qcom,msm-id = <316 0x10001>;
+       qcom,board-id = <0x03010019 0>;
+};
+
+&spi_9 {
+       status = "disabled";
+};
+
+&soc {
+       qcom,msm-ssc-sensors {
+               status = "disabled";
+       };
+
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+
+       i2c@75b6000 { /* BLSP8 */
+               /* ADV7533 HDMI Bridge Chip removed on ADP Lite */
+               adv7533@3d {
+                       status = "disabled";
+               };
+               adv7533@39 {
+                       status = "disabled";
+               };
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
+&slim_msm {
+       status = "disabled";
+};
+
+&pm8994_mpps {
+       mpp@a500 { /* MPP 6 */
+               qcom,mode = <1>;                /* Digital output */
+               qcom,output-type = <0>;         /* CMOS logic */
+               qcom,vin-sel = <2>;             /* S4 1.8V */
+               qcom,src-sel = <0>;             /* Constant */
+               qcom,master-en = <1>;           /* Enable GPIO */
+               status = "okay";
+       };
+};
+
+&sdhc_2 {
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>;
+       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+                       &sdc2_cd_on_sbc>;
+};
+
+&i2c_7 {
+       silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/
+               status = "disabled";
+       };
+};
+
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
new file mode 100644 (file)
index 0000000..497f3f1
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "apq8096pro-v1.1.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-agave-adp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP";
+       compatible = "qcom,apq8096-adp", "qcom,msm8996", "qcom,adp";
+       qcom,msm-id = <316 0x10001>;
+       qcom,board-id = <0x02010019 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <122 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&soc {
+       qcom,msm-ssc-sensors {
+               status = "disabled";
+       };
+
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+
+       qcom,adv7481@70 {
+               qcom,cam-vreg-min-voltage = <1300000 0 1800000>;
+               qcom,cam-vreg-max-voltage = <1300000 0 1800000>;
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
+&slim_msm {
+       status = "disabled";
+};
+
+&pm8994_mpps {
+       mpp@a500 { /* MPP 6 */
+               qcom,mode = <1>;                /* Digital output */
+               qcom,output-type = <0>;         /* CMOS logic */
+               qcom,vin-sel = <2>;             /* S4 1.8V */
+               qcom,src-sel = <0>;             /* Constant */
+               qcom,master-en = <1>;           /* Enable GPIO */
+               status = "okay";
+       };
+};
+
+&sdhc_2 {
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>;
+       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+                       &sdc2_cd_on_sbc>;
+};
+
+&i2c_7 {
+       silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/
+               status = "disabled";
+       };
+};
+
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts
new file mode 100644 (file)
index 0000000..2c54dfe
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8096pro-v1.1.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-auto-cdp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. APQ 8096 pro v1.1 AUTO CDP";
+       compatible = "qcom,msm8996-cdp", "qcom,msm8996", "qcom,cdp";
+       qcom,msm-id = <316 0x10001>;
+       qcom,board-id = <0x03010001 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <127 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1.dtsi b/arch/arm/boot/dts/qcom/apq8096pro-v1.1.dtsi
new file mode 100644 (file)
index 0000000..043309f
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. Common device definitions should be placed inside the
+ * msm8996.dtsi file.
+ */
+
+#include "msm8996pro-v1.1.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. APQ 8096 pro v1.1";
+       qcom,msm-id = <312 0x10001>;
+};
+
+&soc {
+       qcom,rmnet-ipa {
+               status = "disabled";
+       };
+};
+
+&ipa_hw {
+       status = "disabled";
+};
index c8011ff..54a41ab 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 7af82a9..afb0f7b 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index b01c85b..7648478 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index a6e6f15..77bae62 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index 7aeb8e3..2207ab6 100644 (file)
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-skuk-hdk.dtsi"
 
 / {
index 0b808e4..9e7b88a 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd.dtsi"
 
 / {
index e41a66e..a24835e 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index d9b1cb8..03e1e05 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
        qcom,mdss-pref-prim-intf = "hdmi";
 };
 
-&msm_gpu {
-       dma-coherent;
-};
-
 &sde_hdmi {
        qcom,display-type = "primary";
 };
index 5684e18..93887a3 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index 0f315d7..fb5e457 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "apq8098-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd.dtsi"
 
 / {
index 7774a28..1d7836c 100644 (file)
                                15 01 00 00 00 00 02 0b 55
                                15 01 00 00 00 00 02 0c 14
                                15 01 00 00 00 00 02 0d 28
-                               15 01 00 00 00 00 02 0e 00
-                               15 01 00 00 00 00 02 0f 00
+                               15 01 00 00 00 00 02 0e 40
+                               15 01 00 00 00 00 02 0f 80
                                15 01 00 00 00 00 02 10 00
                                15 01 00 00 00 00 02 11 22
                                15 01 00 00 00 00 02 12 0a
                                15 01 00 00 00 00 02 1d 00
                                15 01 00 00 00 00 02 1e 80
                                15 01 00 00 00 00 02 1f 00
-                               15 01 00 00 00 00 02 20 00
+                               15 01 00 00 00 00 02 20 03
                                15 01 00 00 00 00 02 21 03
-                               15 01 00 00 00 00 02 22 22
+                               15 01 00 00 00 00 02 22 25
                                15 01 00 00 00 00 02 23 25
                                15 01 00 00 00 00 02 24 00
                                15 01 00 00 00 00 02 25 a7
-                               15 01 00 00 00 00 02 26 00
+                               15 01 00 00 00 00 02 26 80
                                15 01 00 00 00 00 02 27 a5
                                15 01 00 00 00 00 02 28 06
                                15 01 00 00 00 00 02 29 85
-                               15 01 00 00 00 00 02 2a 3f
+                               15 01 00 00 00 00 02 2a 30
                                15 01 00 00 00 00 02 2b 97
                                15 01 00 00 00 00 02 2f 25
                                15 01 00 00 00 00 02 30 26
                                15 01 00 00 00 00 02 45 00
                                15 01 00 00 00 00 02 46 00
                                15 01 00 00 00 00 02 47 00
-                               15 01 00 00 00 00 02 48 00
+                               15 01 00 00 00 00 02 48 03
                                15 01 00 00 00 00 02 49 03
                                15 01 00 00 00 00 02 4a 00
                                15 01 00 00 00 00 02 4b 00
                                15 01 00 00 00 00 02 4f 4c
                                15 01 00 00 00 00 02 50 0d
                                15 01 00 00 00 00 02 51 0e
-                               15 01 00 00 00 00 02 52 23
+                               15 01 00 00 00 00 02 52 20
                                15 01 00 00 00 00 02 53 97
                                15 01 00 00 00 00 02 54 4b
                                15 01 00 00 00 00 02 55 4c
index 7d3e3d3..6ed6a1b 100644 (file)
@@ -37,6 +37,7 @@
                qcom,mdss-dsi-color-order = "rgb_swap_rgb";
                qcom,mdss-dsi-on-command = [
                                15 01 00 00 00 00 02 fe 0d
+                               15 01 00 00 00 00 02 0b c0
                                15 01 00 00 00 00 02 42 00
                                15 01 00 00 00 00 02 18 08
                                15 01 00 00 00 00 02 08 41
diff --git a/arch/arm/boot/dts/qcom/external-mdm9640.dtsi b/arch/arm/boot/dts/qcom/external-mdm9640.dtsi
new file mode 100644 (file)
index 0000000..4c0170a
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+       mdm0: qcom,mdm0 {
+               compatible = "qcom,ext-mdm9x45";
+               cell-index = <0>;
+               #address-cells = <0>;
+               interrupt-parent = <&mdm0>;
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0xffffffff>;
+               interrupt-names =
+                       "err_fatal_irq",
+                       "status_irq";
+               status = "disabled";
+       };
+
+       mdm1: qcom,mdm1 {
+               compatible = "qcom,ext-mdm9x45";
+               cell-index = <0>;
+               #address-cells = <0>;
+               interrupt-parent = <&mdm1>;
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0xffffffff>;
+               interrupt-names =
+                       "err_fatal_irq",
+                       "status_irq";
+               status = "disabled";
+       };
+
+       mdm2: qcom,mdm2 {
+               compatible = "qcom,ext-mdm9x45";
+               cell-index = <0>;
+               #address-cells = <0>;
+               interrupt-parent = <&mdm2>;
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0xffffffff>;
+               interrupt-names =
+                       "err_fatal_irq",
+                       "status_irq";
+               status = "disabled";
+       };
+};
index ecfff13..da28e56 100644 (file)
                 */
                iommus = <&mmss_smmu 42>;
        };
+
+       iommu_coherent_test_device {
+               compatible = "iommu-debug-test";
+               /*
+                * 43 shouldn't be used by anyone on the mmss_smmu.  We just
+                * need _something_ here to get this node recognized by the
+                * SMMU driver. Our test uses ATOS, which doesn't use SIDs
+                * anyways, so using a dummy value is ok.
+                */
+               iommus = <&mmss_smmu 43>;
+               dma-coherent;
+       };
 };
index c1fa33f..fc26c16 100644 (file)
        status = "ok";
 };
 
+&pcie0 {
+       qcom,phy-sequence = <0x404 0x01 0x00
+                               0x034 0x1c 0x00
+                               0x038 0x10 0x00
+                               0x174 0x33 0x00
+                               0x194 0x06 0x00
+                               0x0c8 0x42 0x00
+                               0x128 0x00 0x00
+                               0x144 0xff 0x00
+                               0x148 0x1f 0x00
+                               0x178 0x01 0x00
+                               0x19c 0x01 0x00
+                               0x18c 0x00 0x00
+                               0x184 0x0a 0x00
+                               0x00c 0x09 0x00
+                               0x0d0 0x82 0x00
+                               0x0e4 0x03 0x00
+                               0x0e0 0x55 0x00
+                               0x0dc 0x55 0x00
+                               0x054 0x00 0x00
+                               0x050 0x1a 0x00
+                               0x04c 0x0a 0x00
+                               0x174 0x33 0x00
+                               0x03c 0x02 0x00
+                               0x040 0x1f 0x00
+                               0x0ac 0x04 0x00
+                               0x078 0x0b 0x00
+                               0x084 0x16 0x00
+                               0x090 0x28 0x00
+                               0x10c 0x00 0x00
+                               0x108 0x80 0x00
+                               0x010 0x01 0x00
+                               0x01c 0x31 0x00
+                               0x020 0x01 0x00
+                               0x014 0x02 0x00
+                               0x018 0x00 0x00
+                               0x024 0x2f 0x00
+                               0x028 0x19 0x00
+                               0x0c4 0x15 0x00
+                               0x070 0x0f 0x00
+                               0x048 0x0f 0x00
+                               0x074 0x19 0x00
+                               0x038 0x10 0x00
+                               0x178 0x00 0x00
+                               0x0c4 0x40 0x00
+                               0x400 0x00 0x00
+                               0x408 0x03 0x00>;
+
+       qcom,port-phy-sequence = <0x1068 0x45 0x00
+                               0x1094 0x06 0x00
+                               0x1310 0x1c 0x00
+                               0x1318 0x17 0x00
+                               0x12d8 0x01 0x00
+                               0x12dc 0x00 0x00
+                               0x12e0 0xdb 0x00
+                               0x1320 0x18 0x00
+                               0x121c 0x04 0x00
+                               0x1210 0x04 0x00
+                               0x1458 0x4c 0x00
+                               0x14a0 0x00 0x00
+                               0x14a4 0x01 0x00
+                               0x14a8 0x05 0x00
+                               0x1248 0x4b 0x00
+                               0x131c 0x14 0x00
+                               0x1454 0x05 0x00
+                               0x1404 0x02 0x00
+                               0x146c 0x00 0x00
+                               0x1460 0xa3 0x00
+                               0x1318 0x19 0x00
+                               0x1428 0x0e 0x00
+                               0x1054 0x08 0x00
+                               0x14f8 0x04 0x00
+                               0x14ec 0x06 0x00
+                               0x104c 0x2e 0x00
+                               0x1404 0x03 0x0a
+                               0x1400 0x00 0x00
+                               0x1408 0x0a 0x00>;
+
+       /delete-property/ qcom,l1-supported;
+       /delete-property/ qcom,l1ss-supported;
+       /delete-property/ qcom,aux-clk-sync;
+};
+
+&pcie1 {
+       qcom,phy-sequence = <0x404 0x01 0x00
+                               0x034 0x1c 0x00
+                               0x038 0x10 0x00
+                               0x174 0x33 0x00
+                               0x194 0x06 0x00
+                               0x0c8 0x42 0x00
+                               0x128 0x00 0x00
+                               0x144 0xff 0x00
+                               0x148 0x1f 0x00
+                               0x178 0x01 0x00
+                               0x19c 0x01 0x00
+                               0x18c 0x00 0x00
+                               0x184 0x0a 0x00
+                               0x00c 0x09 0x00
+                               0x0d0 0x82 0x00
+                               0x0e4 0x03 0x00
+                               0x0e0 0x55 0x00
+                               0x0dc 0x55 0x00
+                               0x054 0x00 0x00
+                               0x050 0x1a 0x00
+                               0x04c 0x0a 0x00
+                               0x174 0x33 0x00
+                               0x03c 0x02 0x00
+                               0x040 0x1f 0x00
+                               0x0ac 0x04 0x00
+                               0x078 0x0b 0x00
+                               0x084 0x16 0x00
+                               0x090 0x28 0x00
+                               0x10c 0x00 0x00
+                               0x108 0x80 0x00
+                               0x010 0x01 0x00
+                               0x01c 0x31 0x00
+                               0x020 0x01 0x00
+                               0x014 0x02 0x00
+                               0x018 0x00 0x00
+                               0x024 0x2f 0x00
+                               0x028 0x19 0x00
+                               0x0c4 0x15 0x00
+                               0x070 0x0f 0x00
+                               0x048 0x0f 0x00
+                               0x074 0x19 0x00
+                               0x038 0x10 0x00
+                               0x178 0x00 0x00
+                               0x0c4 0x40 0x00
+                               0x400 0x00 0x00
+                               0x408 0x03 0x00>;
+
+       qcom,port-phy-sequence = <0x2068 0x45 0x00
+                               0x2094 0x06 0x00
+                               0x2310 0x1c 0x00
+                               0x2318 0x17 0x00
+                               0x22d8 0x01 0x00
+                               0x22dc 0x00 0x00
+                               0x22e0 0xdb 0x00
+                               0x2320 0x18 0x00
+                               0x221c 0x04 0x00
+                               0x2210 0x04 0x00
+                               0x2458 0x4c 0x00
+                               0x24a0 0x00 0x00
+                               0x24a4 0x01 0x00
+                               0x24a8 0x05 0x00
+                               0x2248 0x4b 0x00
+                               0x231c 0x14 0x00
+                               0x2454 0x05 0x00
+                               0x2404 0x02 0x00
+                               0x246c 0x00 0x00
+                               0x2460 0xa3 0x00
+                               0x2318 0x19 0x00
+                               0x2428 0x0e 0x00
+                               0x2054 0x08 0x00
+                               0x24f8 0x04 0x00
+                               0x24ec 0x06 0x00
+                               0x204c 0x2e 0x00
+                               0x2404 0x03 0x0a
+                               0x2400 0x00 0x00
+                               0x2408 0x0a 0x00>;
+
+       qcom,msi-gicm-addr = <0x09BD0040>;
+       qcom,msi-gicm-base = <0x240>;
+
+       /delete-property/ qcom,l1-supported;
+       /delete-property/ qcom,l1ss-supported;
+       /delete-property/ qcom,aux-clk-sync;
+};
+
+&pcie2 {
+       qcom,phy-sequence = <0x404 0x01 0x00
+                               0x034 0x1c 0x00
+                               0x038 0x10 0x00
+                               0x174 0x33 0x00
+                               0x194 0x06 0x00
+                               0x0c8 0x42 0x00
+                               0x128 0x00 0x00
+                               0x144 0xff 0x00
+                               0x148 0x1f 0x00
+                               0x178 0x01 0x00
+                               0x19c 0x01 0x00
+                               0x18c 0x00 0x00
+                               0x184 0x0a 0x00
+                               0x00c 0x09 0x00
+                               0x0d0 0x82 0x00
+                               0x0e4 0x03 0x00
+                               0x0e0 0x55 0x00
+                               0x0dc 0x55 0x00
+                               0x054 0x00 0x00
+                               0x050 0x1a 0x00
+                               0x04c 0x0a 0x00
+                               0x174 0x33 0x00
+                               0x03c 0x02 0x00
+                               0x040 0x1f 0x00
+                               0x0ac 0x04 0x00
+                               0x078 0x0b 0x00
+                               0x084 0x16 0x00
+                               0x090 0x28 0x00
+                               0x10c 0x00 0x00
+                               0x108 0x80 0x00
+                               0x010 0x01 0x00
+                               0x01c 0x31 0x00
+                               0x020 0x01 0x00
+                               0x014 0x02 0x00
+                               0x018 0x00 0x00
+                               0x024 0x2f 0x00
+                               0x028 0x19 0x00
+                               0x0c4 0x15 0x00
+                               0x070 0x0f 0x00
+                               0x048 0x0f 0x00
+                               0x074 0x19 0x00
+                               0x038 0x10 0x00
+                               0x178 0x00 0x00
+                               0x0c4 0x40 0x00
+                               0x400 0x00 0x00
+                               0x408 0x03 0x00>;
+
+       qcom,port-phy-sequence = <0x3068 0x45 0x00
+                               0x3094 0x06 0x00
+                               0x3310 0x1c 0x00
+                               0x3318 0x17 0x00
+                               0x32d8 0x01 0x00
+                               0x32dc 0x00 0x00
+                               0x32e0 0xdb 0x00
+                               0x3320 0x18 0x00
+                               0x321c 0x04 0x00
+                               0x3210 0x04 0x00
+                               0x3458 0x4c 0x00
+                               0x34a0 0x00 0x00
+                               0x34a4 0x01 0x00
+                               0x34a8 0x05 0x00
+                               0x3248 0x4b 0x00
+                               0x331c 0x14 0x00
+                               0x3454 0x05 0x00
+                               0x3404 0x02 0x00
+                               0x346c 0x00 0x00
+                               0x3460 0xa3 0x00
+                               0x3318 0x19 0x00
+                               0x3428 0x0e 0x00
+                               0x3054 0x08 0x00
+                               0x34f8 0x04 0x00
+                               0x34ec 0x06 0x00
+                               0x304c 0x2e 0x00
+                               0x3404 0x03 0x0a
+                               0x3400 0x00 0x00
+                               0x3408 0x0a 0x00>;
+
+       /delete-property/ qcom,l1-supported;
+       /delete-property/ qcom,l1ss-supported;
+       /delete-property/ qcom,aux-clk-sync;
+};
+
 &uartblsp2dm1 {
        status = "ok";
        pinctrl-names = "default";
                                                &mdss_hdmi_cec_suspend>;
 };
 
-#include "msm8996-mdss-panels.dtsi"
+#include "msm8996-sde-display.dtsi"
 
 &mdss_mdp {
        qcom,mdss-pref-prim-intf = "dsi";
 };
 
+&dsi_adv_7533_1 {
+       qcom,dsi-display-active;
+       qcom,dsi-panel = <&dsi_adv7533_1080p>;
+
+       qcom,panel-supply-entries {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               qcom,panel-supply-entry@0 {
+                       reg = <0>;
+                       qcom,supply-name = "vdd";
+                       qcom,supply-min-voltage = <3300000>;
+                       qcom,supply-max-voltage = <3300000>;
+                       qcom,supply-enable-load = <100000>;
+                       qcom,supply-disable-load = <100>;
+               };
+
+               qcom,panel-supply-entry@1 {
+                       reg = <1>;
+                       qcom,supply-name = "vddio";
+                       qcom,supply-min-voltage = <1800000>;
+                       qcom,supply-max-voltage = <1800000>;
+                       qcom,supply-enable-load = <100000>;
+                       qcom,supply-disable-load = <100>;
+               };
+       };
+};
+
+&dsi_adv_7533_2 {
+       qcom,dsi-display-active;
+       qcom,dsi-panel = <&dsi_adv7533_1080p>;
+
+       qcom,panel-supply-entries {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               qcom,panel-supply-entry@0 {
+                       reg = <0>;
+                       qcom,supply-name = "vdd";
+                       qcom,supply-min-voltage = <3300000>;
+                       qcom,supply-max-voltage = <3300000>;
+                       qcom,supply-enable-load = <100000>;
+                       qcom,supply-disable-load = <100>;
+               };
+
+               qcom,panel-supply-entry@1 {
+                       reg = <1>;
+                       qcom,supply-name = "vddio";
+                       qcom,supply-min-voltage = <1800000>;
+                       qcom,supply-max-voltage = <1800000>;
+                       qcom,supply-enable-load = <100000>;
+                       qcom,supply-disable-load = <100>;
+               };
+       };
+};
+
 &mdss_dsi {
        hw-config = "dual_dsi";
 };
 };
 
 &soc {
+       qcom,ntn_avb {
+               compatible = "qcom,ntn_avb";
+
+               ntn-rst-gpio = <&pm8994_gpios 13 0>;
+
+               vdd-ntn-hsic-supply = <&pm8994_l25>;
+               vdd-ntn-pci-supply = <&pm8994_s4>;
+               vdd-ntn-io-supply = <&pm8994_s4>;
+
+               qcom,ntn-rst-delay-msec = <100>;
+               qcom,ntn-rc-num = <1>;
+       };
+
        i2c@75ba000 {
                synaptics@20 {
                        compatible = "synaptics,dsx";
                        clock-names = "iface_clk", "core_clk";
                        clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
                                 <&clock_gcc clk_gcc_blsp2_qup6_i2c_apps_clk>;
+                       status = "disabled";
                };
        };
 
                asoc-codec-names = "msm-stub-codec.1";
        };
 
-       usb_detect {
+       usb_detect: usb_detect {
                compatible = "qcom,gpio-usbdetect";
-               qcom,vbus-det-irq = <&pm8994_gpios 17 0>;
+               qcom,vbus-det-gpio = <&pm8994_gpios 17 0>;
+               interrupt-parent = <&spmi_bus>;
+               interrupts = <0x0 0x9 0x0 IRQ_TYPE_NONE>;
+               interrupt-names ="pmic_id_irq";
+       };
+
+       loopback1: qcom,msm-pcm-loopback-low-latency {
+               compatible = "qcom,msm-pcm-loopback";
+               qcom,msm-pcm-loopback-low-latency;
        };
 
        loopback1: qcom,msm-pcm-loopback-low-latency {
                status = "okay";
        };
 
-       gpio@cc00 { /* GPIO 13 - HPH_EN0 */
-               qcom,mode = <1>;
-               qcom,output-type = <0>;
+       gpio@cc00 { /* GPIO 13 - NTN_RST */
+               qcom,mode = <1>; /* DIGITAL OUT */
+               qcom,output-type = <0>; /* CMOS logic */
                qcom,pull = <5>;
-               qcom,vin-sel = <2>;
+               qcom,vin-sel = <2>; /* 1.8 */
                qcom,out-strength = <1>;
-               qcom,src-sel = <2>;
-               qcom,master-en = <1>;
+               qcom,src-sel = <0>; /* GPIO */
+               qcom,master-en = <1>; /* Enable GPIO */
                status = "okay";
        };
 
 };
 
 &usb3 {
-       interrupt-parent = <&usb3>;
-       interrupts = <0 1 2>;
-       #interrupt-cells = <1>;
-       interrupt-map-mask = <0x0 0xffffffff>;
-       interrupt-map = <0x0 0 &intc 0 133 0
-                        0x0 1 &intc 0 180 0
-                        0x0 2 &spmi_bus 0x0 0x0 0x9 0x0>;
-       interrupt-names = "hs_phy_irq", "pwr_event_irq", "pmic_id_irq";
-
+       extcon = <&usb_detect>;
        vbus_dwc3-supply = <&usb_otg_switch>;
        vdda33-supply = <&pm8994_l24>;
        vdda18-supply = <&pm8994_l12>;
                pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
                clocks = <&clock_gcc clk_bb_clk2_pin>;
                clock-names = "ref_clk";
+               status = "disabled";
        };
 };
 
index a5a6bad..01f67b0 100644 (file)
 };
 
 &soc {
+       qcom,ntn_avb {
+               compatible = "qcom,ntn_avb";
+
+               ntn-rst-gpio = <&pm8994_gpios 13 0>;
+
+               vdd-ntn-hsic-supply = <&pm8994_l25>;
+               vdd-ntn-pci-supply = <&pm8994_s4>;
+               vdd-ntn-io-supply = <&pm8994_s4>;
+
+               qcom,ntn-rst-delay-msec = <100>;
+               qcom,ntn-rc-num = <1>;
+       };
+
        i2c@75ba000 {
                synaptics@20 {
                        compatible = "synaptics,dsx";
                status = "okay";
        };
 
-       gpio@cc00 { /* GPIO 13 - HPH_EN0 */
-               qcom,mode = <1>;
-               qcom,output-type = <0>;
+       gpio@cc00 { /* GPIO 13 - NTN_RST */
+               qcom,mode = <1>; /* DIGITAL OUT */
+               qcom,output-type = <0>; /* CMOS logic */
                qcom,pull = <5>;
-               qcom,vin-sel = <2>;
+               qcom,vin-sel = <2>; /* 1.8 */
                qcom,out-strength = <1>;
-               qcom,src-sel = <2>;
-               qcom,master-en = <1>;
+               qcom,src-sel = <0>; /* GPIO */
+               qcom,master-en = <1>; /* Enable GPIO */
                status = "okay";
        };
 
        /delete-property/ vin-supply;
 };
 
+&pcie0 {
+       /delete-property/ qcom,l1-supported;
+       /delete-property/ qcom,l1ss-supported;
+       /delete-property/ qcom,aux-clk-sync;
+};
+
 &pcie1 {
+       qcom,msi-gicm-addr = <0x09BD0040>;
+       qcom,msi-gicm-base = <0x240>;
+
        /delete-property/ qcom,boot-option;
+       /delete-property/ qcom,l1-supported;
+       /delete-property/ qcom,l1ss-supported;
+       /delete-property/ qcom,aux-clk-sync;
+       /delete-property/ qcom,ep-wakeirq;
 };
 
 &pcie2 {
        wake-gpio = <&tlmm 54 0>;
 
        /delete-property/ qcom,boot-option;
+       /delete-property/ qcom,l1-supported;
+       /delete-property/ qcom,l1ss-supported;
+       /delete-property/ qcom,aux-clk-sync;
+       /delete-property/ qcom,ep-wakeirq;
 };
 
 &wsa881x_211 {
        /delete-property/ qcom,spkr-sd-n-gpio;
 };
 
-&hl7509_en_vreg {
-       status = "ok";
-};
-
-&hl7509_vreg {
-       status = "ok";
-};
-
-&gfx_cpr {
-       vdd-supply = <&hl7509_vreg>;
-       qcom,cpr-step-quot-init-min = <20>;
-       qcom,cpr-step-quot-init-max = <26>;
-       qcom,voltage-step = <10000>;
-       /delete-property/ qcom,cpr-enable;
-};
-
-&gfx_vreg {
-       qcom,cpr-voltage-ceiling =
-               <600000  670000  670000  750000  830000
-                910000  960000 1020000>;
-       qcom,cpr-voltage-floor =
-               <600000  600000  600000  600000  600000
-                600000  600000  600000>;
-};
-
-&pm8994_l3 {
-       regulator-min-microvolt = <875000>;
-       regulator-max-microvolt = <875000>;
-       qcom,init-voltage = <875000>;
-};
-
-&pm8994_l11 {
-       regulator-min-microvolt = <850000>;
-       regulator-max-microvolt = <850000>;
-       qcom,init-voltage = <850000>;
-};
-
-&pm8994_l17 {
-       regulator-min-microvolt = <1800000>;
-       regulator-max-microvolt = <1800000>;
-       qcom,init-voltage = <1800000>;
-};
-
-&pm8994_l23 {
-       regulator-min-microvolt = <1100000>;
-       regulator-max-microvolt = <1100000>;
-       qcom,init-voltage = <1100000>;
-};
-
-&pm8994_l27 {
-       regulator-min-microvolt = <800000>;
-       regulator-max-microvolt = <800000>;
-       qcom,init-voltage = <800000>;
-};
 
-&pm8994_l29 {
-       regulator-min-microvolt = <2500000>;
-       regulator-max-microvolt = <2500000>;
-       qcom,init-voltage = <2500000>;
-};
-
-&rpm_bus {
-       rpm-regulator-ldoa26 {
-               /delete-node/ pm8994_l26_corner;
-               /delete-node/ pm8994_l26_floor_corner;
-
-               pm8994_l26: regulator-l26 {
-                       regulator-min-microvolt = <1100000>;
-                       regulator-max-microvolt = <1100000>;
-                       qcom,init-voltage = <1100000>;
-                       status = "okay";
-               };
-       };
-
-       rpm-regulator-ldoa31 {
-               status = "okay";
-               pm8994_l31: regulator-l31 {
-                       regulator-min-microvolt = <1100000>;
-                       regulator-max-microvolt = <1100000>;
-                       qcom,init-voltage = <1100000>;
-                       status = "okay";
-               };
-       };
-};
index 0b7be6a..ff128ac 100644 (file)
                interrupt-controller;
                #interrupt-cells = <2>;
 
+               /* pin governing mux between QSPI and modem on auto boards */
+               modem_mux: mdm_mux {
+                       mux {
+                               pins = "gpio121";
+                               function = "gpio";
+                       };
+
+                       config {
+                               pins = "gpio121";
+                               drive-strength = <2>;
+                               bias-pull-up;
+                               output-high;
+                       };
+               };
                /* add pingrp for adv7533 */
                pmx_adv7533: pmx_adv7533 {
                        adv7533_0_int_active: adv7533_0_int_active {
index c09b18b..74c964b 100644 (file)
@@ -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
                                                qcom,psci-cpu-mode = <4>;
                                                qcom,latency-us = <80>;
                                                qcom,ss-power = <196>;
-                                               qcom,energy-overhead = <45300>;
+                                               qcom,energy-overhead = <62248>;
                                                qcom,time-overhead = <210>;
                                                qcom,reset-level =
                                                        <LPM_RESET_LVL_PC>;
                                                qcom,psci-cpu-mode = <4>;
                                                qcom,latency-us = <80>;
                                                qcom,ss-power = <196>;
-                                               qcom,energy-overhead = <45300>;
+                                               qcom,energy-overhead = <62248>;
                                                qcom,time-overhead = <210>;
                                                qcom,reset-level =
                                                        <LPM_RESET_LVL_PC>;
                qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
                        <79 379>,   /* qusb2phy_dmse_hv_prim */
                        <80 384>,   /* qusb2phy_dmse_hv_sec */
+                       <81 379>,   /* qusb2phy_dpse_hv_prim */
+                       <82 384>,   /* qusb2phy_dpse_hv_sec */
                        <52 275>,   /* qmp_usb3_lfps_rxterm_irq */
                        <87 358>,   /* ee0_krait_hlos_spmi_periph_irq */
                        <0xff 16>,  /* APCj_qgicdrCpu0HwFaultIrptReq */
                        <0xff 94>,  /* osmmu_CIrpt[0] */
                        <0xff 97>,  /* iommu_nonsecure_irq */
                        <0xff 99>,  /* msm_iommu_pmon_nonsecure_irq */
+                       <0xff 101>, /* camss_jpeg_mmu_cirpt */
                        <0xff 102>, /* osmmu_CIrpt[1] */
                        <0xff 105>, /* iommu_pmon_nonsecure_irq */
                        <0xff 108>, /* osmmu_PMIrpt */
                        <0xff 132>, /* blsp1_qup_irq(5) */
                        <0xff 133>, /* blsp2_qup_irq(0) */
                        <0xff 134>, /* blsp2_qup_irq(1) */
+                       <0xff 135>, /* blsp2_qup_irq(2) */
                        <0xff 138>, /* blsp2_qup_irq(5) */
                        <0xff 140>, /* blsp1_uart_irq(1) */
                        <0xff 146>, /* blsp2_uart_irq(1) */
                        <0xff 165>, /* usb30_hs_phy_irq */
                        <0xff 166>, /* sdc1_pwr_cmd_irq */
                        <0xff 170>, /* sdcc_pwr_cmd_irq */
+                       <0xff 171>, /* usb20_hs_phy_irq */
+                       <0xff 172>, /* usb20_power_event_irq */
                        <0xff 173>, /* sdc1_irq[0] */
                        <0xff 174>, /* o_wcss_apss_smd_med */
                        <0xff 175>, /* o_wcss_apss_smd_low */
                        <0xff 208>,
                        <0xff 210>,
                        <0xff 211>, /* usb_dwc3_otg */
+                       <0xff 212>, /* usb30_power_event_irq */
                        <0xff 215>, /* o_bimc_intr(0) */
                        <0xff 224>, /* spdm_realtime_irq[1] */
                        <0xff 238>, /* crypto_bam_irq[0] */
                        <0xff 295>, /* camss_cpp_mmu_cirpt[0] */
                        <0xff 296>, /* camss_cpp_mmu_pmirpt */
                        <0xff 297>, /* ufs_intrq */
+                       <0xff 298>, /* camss_cpp_mmu_cirpt */
                        <0xff 302>, /* qdss_etrbytecnt_irq */
                        <0xff 310>, /* pcie20_1_int_pls_err */
                        <0xff 311>, /* pcie20_1_int_aer_legacy */
                        <0xff 330>, /* camss_irq4 */
                        <0xff 331>, /* camss_irq5 */
                        <0xff 332>, /* sps */
+                       <0xff 341>, /* camss_irq6 */
                        <0xff 346>, /* camss_irq8 */
                        <0xff 347>, /* camss_irq9 */
                        <0xff 352>, /* mdss_mmu_cirpt[0] */
index 1396f27..061301f 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include "dsi-panel-toshiba-720p-video.dtsi"
-#include "dsi-panel-sharp-dualmipi-wqxga-video.dtsi"
-#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi"
-#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi"
-#include "dsi-panel-nt35597-dsc-wqxga-video.dtsi"
-#include "dsi-panel-jdi-dualmipi-video.dtsi"
-#include "dsi-panel-jdi-dualmipi-cmd.dtsi"
-#include "dsi-panel-jdi-4k-dualmipi-video-nofbc.dtsi"
-#include "dsi-panel-sim-video.dtsi"
-#include "dsi-panel-sim-dualmipi-video.dtsi"
-#include "dsi-panel-sim-cmd.dtsi"
-#include "dsi-panel-sim-dualmipi-cmd.dtsi"
-#include "dsi-panel-nt35597-dsc-wqxga-cmd.dtsi"
-#include "dsi-panel-hx8379a-truly-fwvga-video.dtsi"
-#include "dsi-panel-r69007-dualdsi-wqxga-cmd.dtsi"
+#include "msm8996-mdss-panels.dtsi"
 #include "dsi-panel-jdi-1080p-video.dtsi"
 #include "dsi-panel-sharp-1080p-cmd.dtsi"
 
 
                qcom,dsi-panel = <&dsi_dual_sharp_video>;
                vddio-supply = <&pm8994_l14>;
-               lab-supply = <&lab_regulator>;
-               ibb-supply = <&ibb_regulator>;
-               qcom,dsi-display-active;
+               /delete-property/ lab-supply;
+               /delete-property/ ibb-supply;
+               /delete-property/ qcom,dsi-display-active;
        };
 
        single_dsi_sim_vid: qcom,dsi-display@1 {
 
                qcom,dsi-panel = <&dsi_sim_vid>;
                vddio-supply = <&pm8994_l14>;
-               lab-supply = <&lab_regulator>;
-               ibb-supply = <&ibb_regulator>;
+               /delete-property/ lab-supply;
+               /delete-property/ ibb-supply;
        };
 
        dsi_toshiba_720p_vid: qcom,dsi-display@2 {
                qcom,dsi-panel = <&dsi_sharp_1080_cmd>;
                vddio-supply = <&pm8994_l14>;
                vdd-supply = <&pm8994_l19>;
-               lab-supply = <&lab_regulator>;
-               ibb-supply = <&ibb_regulator>;
+               /delete-property/ lab-supply;
+               /delete-property/ ibb-supply;
        };
 
        sde_wb: qcom,wb-display@0 {
 
                qcom,dsi-panel = <&dsi_dual_nt35597_cmd>;
                vddio-supply = <&pm8994_l14>;
-               lab-supply = <&lab_regulator>;
-               ibb-supply = <&ibb_regulator>;
+               /delete-property/ lab-supply;
+               /delete-property/ ibb-supply;
        };
 
        dsi_dual_nt35597_video_1: qcom,dsi-display@6 {
 
                qcom,dsi-panel = <&dsi_dual_nt35597_video>;
                vddio-supply = <&pm8994_l14>;
-               lab-supply = <&lab_regulator>;
-               ibb-supply = <&ibb_regulator>;
+               /delete-property/ lab-supply;
+               /delete-property/ ibb-supply;
+       };
+
+       dsi_adv_7533_1: qcom,dsi-display@7 {
+               compatible = "qcom,dsi-display";
+               label = "dsi_adv_7533_1";
+               qcom,display-type = "secondary";
+
+               qcom,dsi-ctrl = <&mdss_dsi0>;
+               qcom,dsi-phy = <&mdss_dsi_phy0>;
+               clocks = <&clock_mmss clk_ext_byte0_clk_src>,
+                       <&clock_mmss clk_ext_pclk0_clk_src>;
+               clock-names = "src_byte_clk", "src_pixel_clk";
+
+               qcom,dsi-panel = <&dsi_adv7533_720p>;
+               vddio-supply = <&pm8994_l14>;
+               qcom,bridge-index = <0>;
+       };
+
+       dsi_adv_7533_2: qcom,dsi-display@8 {
+               compatible = "qcom,dsi-display";
+               label = "dsi_adv_7533_2";
+               qcom,display-type = "tertiary";
+
+               qcom,dsi-ctrl = <&mdss_dsi1>;
+               qcom,dsi-phy = <&mdss_dsi_phy1>;
+               clocks = <&clock_mmss clk_ext_byte1_clk_src>,
+                       <&clock_mmss clk_ext_pclk1_clk_src>;
+               clock-names = "src_byte_clk", "src_pixel_clk";
+
+               qcom,dsi-panel = <&dsi_adv7533_720p>;
+               vddio-supply = <&pm8994_l14>;
+               qcom,bridge-index = <1>;
+       };
+
+       msm_ext_disp: qcom,msm_ext_disp {
+               compatible = "qcom,msm-ext-disp";
+
+               ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+                       compatible = "qcom,msm-ext-disp-audio-codec-rx";
+                       qcom,msm_ext_disp = <&msm_ext_disp>;
+               };
+       };
+
+       sde_hdmi: qcom,hdmi-display {
+               compatible = "qcom,hdmi-display";
+               label = "sde_hdmi";
+               qcom,display-type = "primary";
+               qcom,msm_ext_disp = <&msm_ext_disp>;
        };
 };
 
 &mdss_mdp {
-       connectors = <&dsi_dual_sharp_video_1
-               &sde_wb>;
+       connectors = <&mdss_hdmi &sde_hdmi &dsi_adv_7533_1 &dsi_adv_7533_2>;
 };
 
 &dsi_dual_sharp_video {
index cb33df8..f0fa5dc 100644 (file)
                        iommus = <&mdp_smmu 0>;
                };
 
-               smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
-                       compatible = "qcom,smmu_rot_unsec";
-                       iommus = <&rot_smmu 0>;
-               };
-
-               smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
-                       compatible = "qcom,smmu_mdp_sec";
-                       iommus = <&mdp_smmu 1>;
-               };
-
-               smmu_rot_sec: qcom,smmu_rot_sec_cb {
-                       compatible = "qcom,smmu_rot_sec";
-                       iommus = <&rot_smmu 1>;
-               };
-
                /* data and reg bus scale settings */
                qcom,sde-data-bus {
                        qcom,msm-bus,name = "mdss_sde";
diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts
new file mode 100644 (file)
index 0000000..68956d7
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "msm8996-v3.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-agave-adp.dtsi"
+#include "msm8996v3-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996 v3 AUTO ADP";
+       compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp";
+       qcom,msm-id = <310 0x30001>;
+       qcom,board-id = <0x02010019 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <122 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&soc {
+       qcom,msm-ssc-sensors {
+               status = "disabled";
+       };
+
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
+&slim_msm {
+       status = "disabled";
+};
+
+&pm8994_mpps {
+       mpp@a500 { /* MPP 6 */
+               qcom,mode = <1>;                /* Digital output */
+               qcom,output-type = <0>;         /* CMOS logic */
+               qcom,vin-sel = <2>;             /* S4 1.8V */
+               qcom,src-sel = <0>;             /* Constant */
+               qcom,master-en = <1>;           /* Enable GPIO */
+               status = "okay";
+       };
+};
+
+&sdhc_2 {
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>;
+       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+                       &sdc2_cd_on_sbc>;
+};
+
+&i2c_7 {
+       silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/
+               status = "disabled";
+       };
+};
+
index 1c92a9a..8ca2b30 100644 (file)
@@ -15,6 +15,7 @@
 #include "msm8996-v3.dtsi"
 #include "msm8996-pm8994.dtsi"
 #include "msm8996-auto-cdp.dtsi"
+#include "msm8996v3-auto.dtsi"
 
 / {
        model = "Qualcomm Technologies, Inc. MSM 8996 v3 AUTO CDP";
        qcom,board-id = <0x03010001 0>;
 };
 
+&soc {
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
 &spi_9 {
        status = "ok";
        can-controller@0 {
diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp-lite.dts
new file mode 100644 (file)
index 0000000..eb8591b
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8996-v3.dtsi"
+#include "msm8996-pm8994-pm8004.dtsi"
+#include "msm8996-agave-adp.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996 v3 + PM8004 ADP LITE";
+       compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp";
+       qcom,board-id = <0x03010019 0>;
+};
+
+&spi_9 {
+       status = "disabled";
+};
index 398aee9..1752256 100644 (file)
        qcom,pmic-id = <0x20009 0x2000A 0x0 0x0>;
        interrupt-parent = <&intc>;
 
+       chosen {
+               bootargs = "fpsimd.fpsimd_settings=1 app_setting.use_app_setting=1 app_setting.use_32bit_app_setting=1";
+       };
+
        aliases {
                sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
                sdhc2 = &sdhc_2; /* SDC2 SD card slot */
 
        intc: interrupt-controller@09bc0000 {
                compatible = "arm,gic-v3";
+               reg = <0x9bc0000 0x10000>,       /* GICD */
+                     <0x9c00000 0x100000>;      /* GICR * 4 */
                #interrupt-cells = <3>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
                interrupt-controller;
                #redistributor-regions = <1>;
                redistributor-stride = <0x0 0x40000>;
-               reg = <0x09bc0000 0x10000>,       /* GICD */
-                     <0x09c00000 0x100000>;      /* GICR * 4 */
+
                interrupts = <1 9 4>;
+
+               gic-its@09BE0000 {
+                       compatible = "arm,gic-v3-its";
+                       msi-contoller;
+                       reg = <0x9be0000 0x20000>;
+               };
        };
 
        timer {
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
new file mode 100644 (file)
index 0000000..668cb28
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "msm8996pro.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-agave-adp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP LITE";
+       compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp";
+       qcom,msm-id = <315 0x10000>;
+       qcom,board-id = <0x03010019 0>;
+};
+
+&spi_9 {
+       status = "disabled";
+};
+
+&soc {
+       qcom,msm-ssc-sensors {
+               status = "disabled";
+       };
+
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+
+       i2c@75b6000 { /* BLSP8 */
+               /* ADV7533 HDMI Bridge Chip removed on ADP Lite */
+               adv7533@3d {
+                       status = "disabled";
+               };
+               adv7533@39 {
+                       status = "disabled";
+               };
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
+&slim_msm {
+       status = "disabled";
+};
+
+&pm8994_mpps {
+       mpp@a500 { /* MPP 6 */
+               qcom,mode = <1>;                /* Digital output */
+               qcom,output-type = <0>;         /* CMOS logic */
+               qcom,vin-sel = <2>;             /* S4 1.8V */
+               qcom,src-sel = <0>;             /* Constant */
+               qcom,master-en = <1>;           /* Enable GPIO */
+               status = "okay";
+       };
+};
+
+&sdhc_2 {
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>;
+       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+                       &sdc2_cd_on_sbc>;
+};
+
+&i2c_7 {
+       silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/
+               status = "disabled";
+       };
+};
+
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts
new file mode 100644 (file)
index 0000000..1ab8ee9
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "msm8996pro.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-agave-adp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP";
+       compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp";
+       qcom,msm-id = <315 0x10000>;
+       qcom,board-id = <0x02010019 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <122 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&soc {
+       qcom,msm-ssc-sensors {
+               status = "disabled";
+       };
+
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
+&slim_msm {
+       status = "disabled";
+};
+
+&pm8994_mpps {
+       mpp@a500 { /* MPP 6 */
+               qcom,mode = <1>;                /* Digital output */
+               qcom,output-type = <0>;         /* CMOS logic */
+               qcom,vin-sel = <2>;             /* S4 1.8V */
+               qcom,src-sel = <0>;             /* Constant */
+               qcom,master-en = <1>;           /* Enable GPIO */
+               status = "okay";
+       };
+};
+
+&sdhc_2 {
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>;
+       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+                       &sdc2_cd_on_sbc>;
+};
+
+&i2c_7 {
+       silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/
+               status = "disabled";
+       };
+};
+
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts
new file mode 100644 (file)
index 0000000..e104be7
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8996pro.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-auto-cdp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO CDP";
+       compatible = "qcom,msm8996-cdp", "qcom,msm8996", "qcom,cdp";
+       qcom,msm-id = <315 0x10000>;
+       qcom,board-id = <0x03010001 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <127 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
+&soc {
+       qcom,msm-thermal {
+               qcom,hotplug-temp = <115>;
+               qcom,hotplug-temp-hysteresis = <25>;
+               qcom,therm-reset-temp = <119>;
+       };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi b/arch/arm/boot/dts/qcom/msm8996pro-auto.dtsi
new file mode 100644 (file)
index 0000000..48d544e
--- /dev/null
@@ -0,0 +1,461 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8996v3-auto.dtsi"
+
+&gfx_vreg {
+       qcom,cpr-fuse-combos = <24>;
+       qcom,cpr-speed-bins = <3>;
+       qcom,cpr-speed-bin-corners = <8 8 8>;
+       qcom,cpr-corners = <8>;
+
+       qcom,cpr-corner-fmax-map =
+               <2 4 6 8>;
+
+       qcom,cpr-voltage-ceiling =
+               <600000  670000  670000  750000  830000  910000  960000
+               1020000>;
+
+       qcom,cpr-voltage-floor =
+               <600000  600000  600000  600000  600000  600000  600000
+               600000>;
+
+       qcom,mem-acc-voltage =
+               <1 1 1 1 2 2 2 2>;
+
+       qcom,corner-frequencies =
+               <0 133000000 214000000 315000000 401800000 510000000 560000000
+                  624000000>;
+
+       qcom,cpr-target-quotients =
+               <0 0 0 0 0 0    0    0    0    0    0    0 0 0 0 0>,
+               <0 0 0 0 0 0  185  179  291  299  304  319 0 0 0 0>,
+               <0 0 0 0 0 0  287  273  425  426  443  453 0 0 0 0>,
+               <0 0 0 0 0 0  414  392  584  576  608  612 0 0 0 0>,
+               <0 0 0 0 0 0  459  431  684  644  692  679 0 0 0 0>,
+               <0 0 0 0 0 0  577  543  798  768  823  810 0 0 0 0>,
+               <0 0 0 0 0 0  669  629  886  864  924  911 0 0 0 0>,
+               <0 0 0 0 0 0  771  725  984  970 1036 1024 0 0 0 0>;
+
+       qcom,cpr-ro-scaling-factor =
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>,
+               <0 0 0 0 0 0 2035 1917 1959 2131 2246 2253 0 0 0 0>;
+
+       qcom,cpr-open-loop-voltage-fuse-adjustment =
+               <0 (-20000) (-20000) (-40000)>;
+
+       qcom,cpr-closed-loop-voltage-adjustment =
+               <0 0 30000 10000 10000 45000 25000 25000>;
+
+       qcom,cpr-floor-to-ceiling-max-range =
+               <0 70000 70000 75000 80000 90000 95000 100000>;
+
+       qcom,cpr-fused-closed-loop-voltage-adjustment-map =
+               <0 2 2 2 2 0 0 4>;
+};
+
+&apcc_cpr {
+       /delete-property/ qcom,cpr-enable;
+};
+
+&apc0_pwrcl_vreg {
+       regulator-max-microvolt = <19>;
+       qcom,cpr-fuse-combos = <24>;
+       qcom,cpr-speed-bins = <3>;
+       qcom,cpr-speed-bin-corners = <19 19 19>;
+       qcom,cpr-corners = <19>;
+
+       qcom,cpr-corner-fmax-map =
+               <3 6 9 14 19>;
+
+       qcom,cpr-voltage-ceiling =
+               <670000  670000  670000  670000  670000  670000  745000  745000
+                745000  905000  905000  905000  905000  905000 1140000 1140000
+               1140000 1140000 1140000>;
+
+       qcom,cpr-voltage-floor =
+               <470000  470000  470000  470000  470000  470000  470000  470000
+                470000  470000  470000  470000  470000  470000  470000  470000
+                470000  470000  470000>;
+
+       qcom,cpr-floor-to-ceiling-max-range =
+                <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+
+       qcom,corner-frequencies =
+               <307200000  384000000  460800000  537600000  614400000
+                691200000  768000000  844800000  902400000  979200000
+               1056000000 1132800000 1209600000 1286400000 1363200000
+               1440000000 1516800000 1593600000 1785600000>;
+
+       qcom,cpr-open-loop-voltage-fuse-adjustment =
+               <0        0        0        0        0 >;
+
+       qcom,cpr-closed-loop-voltage-fuse-adjustment =
+               <0        0        0        0        0 >;
+
+       qcom,cpr-open-loop-voltage-adjustment =
+               <0 0 0 0 0 0 0 0 0 (-2000) (-4000) (-6000) (-8000) (-10000)
+                (-11000) (-12000) (-12000) (-13000) (-15000)>;
+
+       qcom,cpr-open-loop-voltage-min-diff =
+               <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+
+       qcom,cpr-closed-loop-voltage-adjustment =
+               <0 0 0 0 0 0 0 0 0 (-2000) (-4000) (-6000) (-8000) (-10000)
+                (-11000) (-12000) (-12000) (-13000) (-15000)>;
+
+       qcom,allow-aging-voltage-adjustment = <0>;
+       qcom,allow-aging-open-loop-voltage-adjustment = <0>;
+};
+
+&apc0_cbf_vreg {
+       qcom,cpr-fuse-combos = <24>;
+       qcom,cpr-speed-bins = <3>;
+       qcom,cpr-speed-bin-corners = <19 19 19>;
+       qcom,cpr-corners = <19>;
+
+       qcom,cpr-corner-fmax-map =
+               <1 4 7 14 19>;
+
+       qcom,cpr-voltage-ceiling =
+               <670000  670000  670000  670000  745000  745000  745000  905000
+                905000  905000  905000  905000  905000  905000 1140000 1140000
+               1140000 1140000 1140000>;
+
+       qcom,cpr-voltage-floor =
+               <470000  470000  470000  470000  470000  470000  470000  470000
+                470000  470000  470000  470000  470000  470000  470000  470000
+                470000  470000  470000>;
+
+       qcom,cpr-floor-to-ceiling-max-range =
+                <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+
+       qcom,corner-frequencies =
+               <192000000  307200000  384000000  441600000  537600000
+                614400000  691200000  768000000  844800000  902400000
+                979200000 1056000000 1132800000 1190400000 1286400000
+               1363200000 1440000000 1516800000 1593600000>;
+
+       qcom,cpr-open-loop-voltage-fuse-adjustment =
+               <0        0        0    15000        0 >;
+
+       qcom,cpr-closed-loop-voltage-fuse-adjustment =
+               <0        0        0        0        0 >;
+
+       qcom,allow-aging-voltage-adjustment = <0>;
+       qcom,allow-aging-open-loop-voltage-adjustment = <0>;
+};
+
+&apc1_vreg {
+       qcom,cpr-fuse-combos = <24>;
+       qcom,cpr-speed-bins = <3>;
+       qcom,cpr-speed-bin-corners = <25 25 25>;
+       qcom,cpr-corners = <25>;
+
+       qcom,cpr-corner-fmax-map =
+               <4 7 10 15 25>;
+
+       qcom,cpr-voltage-ceiling =
+               <670000  670000  670000  670000  670000  670000  670000  745000
+                745000  745000  905000  905000  905000  905000  905000 1140000
+               1140000 1140000 1140000 1140000 1140000 1140000 1140000 1140000
+               1140000>;
+
+       qcom,cpr-voltage-floor =
+               <470000  470000  470000  470000  470000  470000  470000  470000
+                470000  470000  470000  470000  470000  470000  470000  470000
+                470000  470000  470000  470000  470000  470000  470000  470000
+                470000>;
+
+       qcom,cpr-floor-to-ceiling-max-range =
+                <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+
+       qcom,corner-frequencies =
+               <307200000  384000000  460800000  537600000  614400000
+                691200000  748800000  825600000  902400000  979200000
+               1056000000 1132800000 1209600000 1286400000 1363200000
+               1440000000 1516800000 1593600000 1670400000 1747200000
+               1824000000 1900800000 1977600000 2054400000 2150400000>;
+
+       qcom,cpr-open-loop-voltage-fuse-adjustment =
+               <0        0        0        0        0 >;
+
+       qcom,cpr-closed-loop-voltage-fuse-adjustment =
+               <0        0        0        0        0 >;
+
+       qcom,cpr-open-loop-voltage-adjustment =
+                <0 0 0 0 0 0 0 0 0 0 (-2000) (-4000) (-6000) (-8000) (-10000)
+                 (-10000) (-11000) (-11000) (-12000) (-12000) (-13000) (-13000)
+                 (-14000) (-14000) (-15000)>;
+
+       qcom,cpr-open-loop-voltage-min-diff =
+                <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+
+       qcom,cpr-closed-loop-voltage-adjustment =
+                <0 0 0 0 0 0 0 0 0 0 (-2000) (-4000) (-6000) (-8000) (-10000)
+                 (-10000) (-11000) (-11000) (-12000) (-12000) (-13000) (-13000)
+                 (-14000) (-14000) (-15000)>;
+
+       qcom,allow-aging-voltage-adjustment = <0>;
+       qcom,allow-aging-open-loop-voltage-adjustment = <0>;
+};
+
+&clock_cpu {
+       compatible = "qcom,cpu-clock-8996-auto";
+       qcom,pwrcl-early-boot-freq = < 1286400000 >;
+       qcom,perfcl-early-boot-freq = < 1363200000 >;
+
+       qcom,pwrcl-speedbin0-v0 =
+               <          0  0 >,
+               <  768000000  7 >,
+               <  844800000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >;
+
+       qcom,pwrcl-speedbin1-v0 =
+               <          0  0 >,
+               <  768000000  7 >,
+               <  844800000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >;
+
+       qcom,pwrcl-speedbin2-v0 =
+               <          0  0 >,
+               <  768000000  7 >,
+               <  844800000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >;
+
+       qcom,perfcl-speedbin0-v0 =
+               <          0  0 >,
+               <  825600000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >,
+               < 1670400000 19 >,
+               < 1747200000 20 >,
+               < 1824000000 21 >,
+               < 1900800000 22 >,
+               < 1977600000 23 >,
+               < 2054400000 24 >;
+
+       qcom,perfcl-speedbin1-v0 =
+               <          0  0 >,
+               <  825600000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >,
+               < 1670400000 19 >;
+
+       qcom,perfcl-speedbin2-v0 =
+               <          0  0 >,
+               <  825600000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >;
+
+       qcom,cbf-speedbin0-v0 =
+               <          0  0 >,
+               <  537600000  5 >,
+               <  614400000  6 >,
+               <  691200000  7 >,
+               <  768000000  8 >,
+               <  844800000  9 >,
+               <  902400000 10 >,
+               <  979200000 11 >,
+               < 1056000000 12 >,
+               < 1132800000 13 >,
+               < 1190400000 14 >,
+               < 1286400000 15 >,
+               < 1363200000 16 >,
+               < 1440000000 17 >,
+               < 1516800000 18 >,
+               < 1593600000 19 >;
+
+       qcom,cbf-speedbin1-v0 =
+               <          0  0 >,
+               <  537600000  5 >,
+               <  614400000  6 >,
+               <  691200000  7 >,
+               <  768000000  8 >,
+               <  844800000  9 >,
+               <  902400000 10 >,
+               <  979200000 11 >,
+               < 1056000000 12 >,
+               < 1132800000 13 >,
+               < 1190400000 14 >,
+               < 1286400000 15 >,
+               < 1363200000 16 >,
+               < 1440000000 17 >,
+               < 1516800000 18 >,
+               < 1593600000 19 >;
+
+       qcom,cbf-speedbin2-v0 =
+               <          0  0 >,
+               <  537600000  5 >,
+               <  614400000  6 >,
+               <  691200000  7 >,
+               <  768000000  8 >,
+               <  844800000  9 >,
+               <  902400000 10 >,
+               <  979200000 11 >,
+               < 1056000000 12 >,
+               < 1132800000 13 >,
+               < 1190400000 14 >;
+};
+
+&msm_cpufreq {
+       qcom,cpufreq-table-0 =
+               <  768000 >,
+               <  844800 >,
+               <  902400 >,
+               <  979200 >,
+               < 1056000 >,
+               < 1132800 >,
+               < 1209600 >,
+               < 1286400 >,
+               < 1363200 >,
+               < 1440000 >,
+               < 1516800 >,
+               < 1593600 >;
+       qcom,cpufreq-table-2 =
+               <  825600 >,
+               <  902400 >,
+               <  979200 >,
+               < 1056000 >,
+               < 1132800 >,
+               < 1209600 >,
+               < 1286400 >,
+               < 1363200 >,
+               < 1440000 >,
+               < 1516800 >,
+               < 1593600 >,
+               < 1670400 >,
+               < 1747200 >,
+               < 1824000 >,
+               < 1900800 >,
+               < 1977600 >,
+               < 2054400 >;
+};
+
+&m4m_cache {
+       freq-tbl-khz =
+               <  537600 >,
+               <  614400 >,
+               <  691200 >,
+               <  768000 >,
+               <  844800 >,
+               <  902400 >,
+               <  979200 >,
+               < 1056000 >,
+               < 1132800 >,
+               < 1190400 >,
+               < 1286400 >,
+               < 1363200 >,
+               < 1440000 >,
+               < 1516800 >,
+               < 1593600 >;
+};
+
+&devfreq_cpufreq {
+       mincpubw-cpufreq {
+               cpu-to-dev-map-0 =
+                       < 1593600 1525 >;
+               cpu-to-dev-map-2 =
+                       < 1977600 1525 >,
+                       < 2054400 5195 >;
+       };
+};
+
+&clock_gpu {
+       qcom,gfxfreq-speedbin0 =
+               <          0  0  0 >,
+               <  315000000  4  4 >,
+               <  401800000  5  5 >,
+               <  510000000  6  5 >,
+               <  560000000  7  7 >,
+               <  624000000  8  7 >;
+
+       qcom,gfxfreq-mx-speedbin0 =
+               <          0  0 >,
+               <  315000000  4 >,
+               <  401800000  5 >,
+               <  510000000  5 >,
+               <  560000000  7 >,
+               <  624000000  7 >;
+
+       qcom,gfxfreq-speedbin1 =
+               <          0  0  0 >,
+               <  315000000  4  4 >,
+               <  401800000  5  5 >,
+               <  510000000  6  5 >;
+
+       qcom,gfxfreq-mx-speedbin1 =
+               <          0  0 >,
+               <  315000000  4 >,
+               <  401800000  5 >,
+               <  510000000  5 >;
+
+       qcom,gfxfreq-speedbin2 =
+               <          0  0  0 >,
+               <  315000000  4  4 >;
+
+       qcom,gfxfreq-mx-speedbin2 =
+               <          0  0 >,
+               <  315000000  4 >;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts
new file mode 100644 (file)
index 0000000..06d040a
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8996pro-v1.1.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996-auto-cdp.dtsi"
+#include "msm8996pro-auto.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. MSM 8996pro v1.1 AUTO CDP";
+       compatible = "qcom,msm8996-cdp", "qcom,msm8996", "qcom,cdp";
+       qcom,msm-id = <315 0x10001>;
+       qcom,board-id = <0x03010001 0>;
+};
+
+&spi_9 {
+       status = "ok";
+       can-controller@0 {
+               compatible = "renesas,rh850";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <127 0>;
+               spi-max-frequency = <5000000>;
+       };
+};
+
+&pil_modem {
+       pinctrl-names = "default";
+       pinctrl-0 = <&modem_mux>;
+};
+
index 28577dc..2f29fab 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
 / {
        model = "Qualcomm Technologies, Inc. MSM 8996pro";
        qcom,msm-id = <305 0x10000>;
+
+       chosen {
+               bootargs = "fpsimd.fpsimd_settings=1 app_setting.use_app_setting=0 app_setting.use_32bit_app_setting_pro=1";
+       };
 };
 
 &apc_apm {
                < 1516800000 17 >,
                < 1593600000 18 >,
                < 1996800000 20 >;
+       qcom,pwrcl-speedbin2-v0 =
+               <          0  0 >,
+               <  307200000  1 >,
+               <  384000000  2 >,
+               <  460800000  3 >,
+               <  537600000  4 >,
+               <  614400000  5 >,
+               <  691200000  6 >,
+               <  768000000  7 >,
+               <  844800000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >;
        qcom,perfcl-speedbin0-v0 =
                <          0  0 >,
                <  307200000  1 >,
                < 1977600000 23 >,
                < 2054400000 24 >,
                < 2150400000 25 >;
+       qcom,perfcl-speedbin2-v0 =
+               <          0  0 >,
+               <  307200000  1 >,
+               <  384000000  2 >,
+               <  460800000  3 >,
+               <  537600000  4 >,
+               <  614400000  5 >,
+               <  691200000  6 >,
+               <  748800000  7 >,
+               <  825600000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >,
+               < 1670400000 19 >,
+               < 1747200000 20 >,
+               < 1824000000 21 >,
+               < 1900800000 22 >;
        qcom,cbf-speedbin0-v0 =
                <          0  0 >,
                <  192000000  1 >,
                < 1440000000 17 >,
                < 1516800000 18 >,
                < 1593600000 19 >;
+       qcom,cbf-speedbin2-v0 =
+               <          0  0 >,
+               <  192000000  1 >,
+               <  307200000  2 >,
+               <  384000000  3 >,
+               <  441600000  4 >,
+               <  537600000  5 >,
+               <  614400000  6 >,
+               <  691200000  7 >,
+               <  768000000  8 >,
+               <  844800000  9 >,
+               <  902400000 10 >,
+               <  979200000 11 >,
+               < 1056000000 12 >,
+               < 1132800000 13 >,
+               < 1190400000 14 >,
+               < 1286400000 15 >,
+               < 1363200000 16 >,
+               < 1440000000 17 >,
+               < 1516800000 18 >,
+               < 1593600000 19 >;
 };
 
 &clock_mmss {
                <  510000000  5 >,
                <  560000000  7 >,
                <  624000000  7 >;
+       qcom,gfxfreq-speedbin2 =
+               <          0  0  0 >,
+               <  133000000  2  4 >,
+               <  214000000  3  4 >,
+               <  315000000  4  4 >,
+               <  401800000  5  5 >,
+               <  510000000  6  5 >;
+       qcom,gfxfreq-mx-speedbin2 =
+               <          0  0 >,
+               <  133000000  4 >,
+               <  214000000  4 >,
+               <  315000000  4 >,
+               <  401800000  5 >,
+               <  510000000  5 >;
 };
 
 &msm_cpufreq {
diff --git a/arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi b/arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi
new file mode 100644 (file)
index 0000000..32adb9a
--- /dev/null
@@ -0,0 +1,169 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&hl7509_en_vreg {
+       status = "ok";
+};
+
+&hl7509_vreg {
+       status = "ok";
+};
+
+&gfx_cpr {
+       vdd-supply = <&hl7509_vreg>;
+       qcom,cpr-step-quot-init-min = <20>;
+       qcom,cpr-step-quot-init-max = <26>;
+       qcom,voltage-step = <10000>;
+       /delete-property/ qcom,cpr-enable;
+};
+
+&gfx_vreg {
+       qcom,cpr-voltage-ceiling =
+               <600000  670000  670000  750000  830000
+                910000  960000 1020000>;
+       qcom,cpr-voltage-floor =
+               <600000  600000  600000  600000  600000
+                600000  600000  600000>;
+};
+
+&pm8994_l3 {
+       regulator-min-microvolt = <875000>;
+       regulator-max-microvolt = <875000>;
+       qcom,init-voltage = <875000>;
+};
+
+&pm8994_l11 {
+       regulator-min-microvolt = <850000>;
+       regulator-max-microvolt = <850000>;
+       qcom,init-voltage = <850000>;
+};
+
+&pm8994_l17 {
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       qcom,init-voltage = <1800000>;
+};
+
+&pm8994_l23 {
+       regulator-min-microvolt = <1100000>;
+       regulator-max-microvolt = <1100000>;
+       qcom,init-voltage = <1100000>;
+};
+
+&pm8994_l27 {
+       regulator-min-microvolt = <800000>;
+       regulator-max-microvolt = <800000>;
+       qcom,init-voltage = <800000>;
+};
+
+&pm8994_l29 {
+       regulator-min-microvolt = <2500000>;
+       regulator-max-microvolt = <2500000>;
+       qcom,init-voltage = <2500000>;
+};
+
+&rpm_bus {
+       rpm-regulator-ldoa26 {
+               /delete-node/ pm8994_l26_corner;
+               /delete-node/ pm8994_l26_floor_corner;
+
+               pm8994_l26: regulator-l26 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+                       qcom,init-voltage = <1100000>;
+                       status = "okay";
+               };
+       };
+
+       rpm-regulator-ldoa31 {
+               status = "okay";
+               pm8994_l31: regulator-l31 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+                       qcom,init-voltage = <1100000>;
+                       status = "okay";
+               };
+       };
+};
+
+&clock_cpu {
+       qcom,pwrcl-speedbin0-v0 =
+               <          0  0 >,
+               <  768000000  7 >,
+               <  844800000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >;
+
+       qcom,perfcl-speedbin0-v0 =
+               <          0  0 >,
+               <  825600000  8 >,
+               <  902400000  9 >,
+               <  979200000 10 >,
+               < 1056000000 11 >,
+               < 1132800000 12 >,
+               < 1209600000 13 >,
+               < 1286400000 14 >,
+               < 1363200000 15 >,
+               < 1440000000 16 >,
+               < 1516800000 17 >,
+               < 1593600000 18 >,
+               < 1670400000 19 >,
+               < 1747200000 20 >,
+               < 1824000000 21 >,
+               < 1900800000 22 >,
+               < 1977600000 23 >,
+               < 2054400000 24 >;
+
+       qcom,cbf-speedbin0-v0 =
+               <          0  0 >,
+               <  537600000  5 >,
+               <  614400000  6 >,
+               <  691200000  7 >,
+               <  768000000  8 >,
+               <  844800000  9 >,
+               <  902400000 10 >,
+               <  979200000 11 >,
+               < 1056000000 12 >,
+               < 1132800000 13 >,
+               < 1190400000 14 >,
+               < 1286400000 15 >,
+               < 1363200000 16 >,
+               < 1440000000 17 >,
+               < 1516800000 18 >,
+               < 1593600000 19 >;
+};
+
+&clock_gpu {
+       qcom,gfxfreq-speedbin0 =
+               <          0  0  0 >,
+               <  315000000  4  4 >,
+               <  401800000  5  5 >,
+               <  510000000  6  5 >,
+               <  560000000  7  7 >,
+               <  624000000  8  7 >;
+
+       qcom,gfxfreq-mx-speedbin0 =
+               <          0  0 >,
+               <  315000000  4 >,
+               <  401800000  5 >,
+               <  510000000  5 >,
+               <  560000000  7 >,
+               <  624000000  7 >;
+};
index 5fe0d01..9cf9401 100644 (file)
@@ -18,6 +18,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 487d71d..3d8ccbd 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 2b9e13e..1b746a5 100644 (file)
                                qcom,supply-max-voltage = <0>;
                                qcom,supply-enable-load = <0>;
                                qcom,supply-disable-load = <0>;
+                               qcom,supply-lp-mode-disable-allowed;
                        };
                };
 
                                qcom,supply-max-voltage = <880000>;
                                qcom,supply-enable-load = <73400>;
                                qcom,supply-disable-load = <32>;
+                               qcom,supply-lp-mode-disable-allowed;
                        };
                };
 
                qcom,pluggable;
        };
 };
-
-#include "msm8998-mdss-panels.dtsi"
index 8525d78..0659ced 100644 (file)
@@ -18,6 +18,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index f608f5f..8a38d1e 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index 220bad3..cdf4bed 100644 (file)
                                        bias-pull-down;
                                };
                        };
+
+                       pcie0_wake_sleep: pcie0_wake_sleep {
+                               mux {
+                                       pins = "gpio37";
+                                       function = "gpio";
+                               };
+
+                               config {
+                                       pins = "gpio37";
+                                       drive-strength = <2>;
+                                       bias-disable;
+                               };
+                       };
                };
 
                hph_en0_ctrl {
index 753f01e..b3062c4 100644 (file)
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-skuk.dtsi"
 #include "msm8998-camera-sensor-skuk.dtsi"
 
index f578052..9b8e631 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-vr1.dtsi"
 
 / {
index 952b9a5..4d50d86 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd.dtsi"
 
 / {
index 045cdda..be70f12 100644 (file)
@@ -84,6 +84,8 @@
                pm8998_s5: regulator-s5 {
                        regulator-min-microvolt = <1904000>;
                        regulator-max-microvolt = <2040000>;
+                       qcom,init-pin-ctrl-mode = <8>;          /* PMIC_AWAKE */
+                       qcom,send-defaults;
                        status = "okay";
                };
        };
@@ -93,6 +95,8 @@
                pm8998_s7: regulator-s7 {
                        regulator-min-microvolt = <900000>;
                        regulator-max-microvolt = <1028000>;
+                       qcom,init-pin-ctrl-mode = <8>;          /* PMIC_AWAKE */
+                       qcom,send-defaults;
                        status = "okay";
                };
        };
        rpm-regulator-ldoa24 {
                status = "okay";
                pm8998_l24: regulator-l24 {
-                       regulator-min-microvolt = <3088000>;
+                       regulator-min-microvolt = <1848000>;
                        regulator-max-microvolt = <3088000>;
                        parent-supply = <&pm8998_l12>;
                        status = "okay";
index c602459..1ae6716 100644 (file)
@@ -18,6 +18,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 0f5ad53..f54017d 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 660fc4d..c446a6a 100644 (file)
@@ -18,6 +18,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index 0708573..0375ee2 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index a64f620..b1d00ed 100644 (file)
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-skuk.dtsi"
 #include "msm8998-camera-sensor-skuk-evt3.dtsi"
 
index f3ba42e..4e75d16 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-skuk-hdk.dtsi"
 
 / {
index 7e7eb96..5727f33 100644 (file)
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-skuk.dtsi"
 #include "msm8998-camera-sensor-skuk.dtsi"
 
index 58c7dc3..ebd5b30 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd-vr1.dtsi"
 
 / {
index 37ad182..ed3a73e 100644 (file)
@@ -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
@@ -13,6 +13,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd.dtsi"
 
 / {
index 47c55a0..f572389 100644 (file)
@@ -18,6 +18,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 871d13b..5d007dd 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-cdp.dtsi"
 
 / {
index 6884397..6e4247f 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.1-interposer-sdm660.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-interposer-sdm660-cdp.dtsi"
 #include "msm8998-interposer-pm660.dtsi"
 #include "msm8998-interposer-sdm660-audio.dtsi"
index 2e5de95..cb7ee22 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.1-interposer-sdm660.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-interposer-sdm660-mtp.dtsi"
 #include "msm8998-interposer-pm660.dtsi"
 #include "msm8998-interposer-sdm660-audio.dtsi"
index 180cc91..9376f52 100644 (file)
@@ -13,6 +13,8 @@
 
 /dts-v1/;
 
+#include "msm8998-v2.1-interposer-sdm660.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-v2.1-interposer-sdm660-qrd.dtsi"
 #include "msm8998-interposer-pm660.dtsi"
 #include "msm8998-interposer-sdm660-audio.dtsi"
index 7d537aa..eb2d812 100644 (file)
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index 54a0e98..5f17f73 100644 (file)
@@ -18,6 +18,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index 9d7cbc9..0bf3e62 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-mtp.dtsi"
 
 / {
index b20c888..4d64740 100644 (file)
@@ -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
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "msm8998-v2.1.dtsi"
+#include "msm8998-mdss-panels.dtsi"
 #include "msm8998-qrd.dtsi"
 
 / {
index 9b5092c..c1d785e 100644 (file)
                                        0x800 0x00 0x00
                                        0x808 0x03 0x00>;
 
-               pinctrl-names = "default";
+               pinctrl-names = "default", "sleep";
                pinctrl-0 = <&pcie0_clkreq_default
                        &pcie0_perst_default
                        &pcie0_wake_default>;
+               pinctrl-1 = <&pcie0_clkreq_default
+                       &pcie0_perst_default
+                       &pcie0_wake_sleep>;
 
                perst-gpio = <&tlmm 35 0>;
                wake-gpio = <&tlmm 37 0>;
                         <&clock_gcc clk_rf_clk3_pin>;
                clock-names = "rf_clk3_clk", "rf_clk3_pin_clk";
                qcom,smmu-support;
+               qcom,smmu-s1-en;
+               qcom,smmu-fast-map;
+               qcom,smmu-coherent;
+               qcom,smmu-mapping = <0x20000000 0xe0000000>;
                status = "disabled";
        };
 
index c677df5..5fac5ce 100644 (file)
 &pm660_fg {
        qcom,battery-data = <&qrd_batterydata>;
        qcom,fg-jeita-thresholds = <0 5 55 55>;
+       qcom,battery-thermal-coefficients = [9d 50 ff];
 };
 
 &uartblsp1dm1 {
index 3d2cfed..86da804 100644 (file)
 &pm660_fg {
        qcom,battery-data = <&qrd_batterydata>;
        qcom,fg-jeita-thresholds = <0 5 55 55>;
+       qcom,battery-thermal-coefficients = [9d 50 ff];
 };
 
 &i2c_2 {
index a8844da..fe6988e 100644 (file)
@@ -3,6 +3,9 @@ CONFIG_AUDIT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_RCU_EXPERT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
@@ -242,7 +245,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
 CONFIG_HDCP_QSEECOM=y
-CONFIG_UID_CPUTIME=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_QPNP_MISC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -527,7 +530,6 @@ CONFIG_MSM_MMCC_660=y
 CONFIG_CLOCK_CPU_OSM=y
 CONFIG_QCOM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
-CONFIG_IOMMU_IO_PGTABLE_FAST=y
 CONFIG_ARM_SMMU=y
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_DEBUG_TRACKING=y
index 30a7190..3942da1 100644 (file)
@@ -3,6 +3,9 @@ CONFIG_AUDIT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_RCU_EXPERT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -241,7 +244,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
 CONFIG_HDCP_QSEECOM=y
-CONFIG_UID_CPUTIME=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_QPNP_MISC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -526,8 +529,6 @@ CONFIG_MSM_MMCC_660=y
 CONFIG_CLOCK_CPU_OSM=y
 CONFIG_QCOM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
-CONFIG_IOMMU_IO_PGTABLE_FAST=y
-CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
 CONFIG_ARM_SMMU=y
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_DEBUG_TRACKING=y
@@ -642,7 +643,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y
 CONFIG_DEBUG_OBJECTS_WORK=y
 CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
-CONFIG_SLUB_DEBUG_ON=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
index 4f8e9e5..d54f8fe 100644 (file)
@@ -1,14 +1,25 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
 #ifndef ASMARM_DMA_CONTIGUOUS_H
 #define ASMARM_DMA_CONTIGUOUS_H
 
 #ifdef __KERNEL__
-#ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
 
 void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
 
 #endif
-#endif
 
 #endif
index 7678724..33ee522 100644 (file)
@@ -301,6 +301,14 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
                next = kvm_pgd_addr_end(addr, end);
                if (!pgd_none(*pgd))
                        unmap_puds(kvm, pgd, addr, next);
+               /*
+                * If we are dealing with a large range in
+                * stage2 table, release the kvm->mmu_lock
+                * to prevent starvation and lockup detector
+                * warnings.
+                */
+               if (kvm && (next != end))
+                       cond_resched_lock(&kvm->mmu_lock);
        } while (pgd++, addr = next, addr != end);
 }
 
@@ -745,6 +753,7 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
  */
 static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size)
 {
+       assert_spin_locked(&kvm->mmu_lock);
        unmap_range(kvm, kvm->arch.pgd, start, size);
 }
 
@@ -803,6 +812,7 @@ void stage2_unmap_vm(struct kvm *kvm)
        int idx;
 
        idx = srcu_read_lock(&kvm->srcu);
+       down_read(&current->mm->mmap_sem);
        spin_lock(&kvm->mmu_lock);
 
        slots = kvm_memslots(kvm);
@@ -810,6 +820,7 @@ void stage2_unmap_vm(struct kvm *kvm)
                stage2_unmap_memslot(kvm, memslot);
 
        spin_unlock(&kvm->mmu_lock);
+       up_read(&current->mm->mmap_sem);
        srcu_read_unlock(&kvm->srcu, idx);
 }
 
@@ -829,7 +840,10 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
        if (kvm->arch.pgd == NULL)
                return;
 
+       spin_lock(&kvm->mmu_lock);
        unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+       spin_unlock(&kvm->mmu_lock);
+
        kvm_free_hwpgd(kvm_get_hwpgd(kvm));
        if (KVM_PREALLOC_LEVEL > 0)
                kfree(kvm->arch.pgd);
@@ -1771,6 +1785,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
            (KVM_PHYS_SIZE >> PAGE_SHIFT))
                return -EFAULT;
 
+       down_read(&current->mm->mmap_sem);
        /*
         * A memory region could potentially cover multiple VMAs, and any holes
         * between them, so iterate over all of them to find out if we can map
@@ -1814,8 +1829,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
                        pa += vm_start - vma->vm_start;
 
                        /* IO region dirty page logging not allowed */
-                       if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES)
-                               return -EINVAL;
+                       if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
 
                        ret = kvm_phys_addr_ioremap(kvm, gpa, pa,
                                                    vm_end - vm_start,
@@ -1827,7 +1844,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
        } while (hva < reg_end);
 
        if (change == KVM_MR_FLAGS_ONLY)
-               return ret;
+               goto out;
 
        spin_lock(&kvm->mmu_lock);
        if (ret)
@@ -1835,6 +1852,8 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
        else
                stage2_flush_memslot(kvm, memslot);
        spin_unlock(&kvm->mmu_lock);
+out:
+       up_read(&current->mm->mmap_sem);
        return ret;
 }
 
index 69f0851..0c369a5 100644 (file)
@@ -540,6 +540,37 @@ config ARM64_64K_PAGES
 
 endchoice
 
+config MSM_APP_API
+       bool "API support to enable / disable app settings for MSM8996"
+       depends on ARCH_MSM8996 && (ENABLE_FP_SIMD_SETTINGS || MSM_APP_SETTINGS)
+       help
+         Add API support to enable / disable the app settings to be used
+         at runtime. These APIs are used to enable / disable app setting
+         when specific aarch32 or aarch64 processes are running.
+
+         If you are not sure what to do, select 'N' here.
+
+config ENABLE_FP_SIMD_SETTINGS
+       bool "Enable FP(Floating Point) Settings for Qualcomm MSM8996"
+       depends on ARCH_MSM8996
+       select MSM_APP_API
+       help
+         Enable FP(Floating Point) and SIMD settings for the MSM8996 during
+         the execution of the aarch32 processes and disable these settings
+         when you switch to the aarch64 processes.
+
+         If you are not sure what to do, select 'N' here.
+
+config MSM_APP_SETTINGS
+       bool "Support to enable / disable app settings for MSM8996"
+       depends on ARCH_MSM8996
+       select MSM_APP_API
+       help
+         Expose an interface used by the userspace at runtime to
+         enable / disable the app specific settings.
+
+         If you are not sure what to do, select 'N' here.
+
 choice
        prompt "Virtual address space size"
        default ARM64_VA_BITS_39 if ARM64_4K_PAGES
diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig
new file mode 100644 (file)
index 0000000..a42cc93
--- /dev/null
@@ -0,0 +1,635 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8996=y
+CONFIG_PCI=y
+CONFIG_PCI_MSM=y
+CONFIG_ENABLE_FP_SIMD_SETTINGS=y
+CONFIG_MSM_APP_SETTINGS=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
+CONFIG_CMA=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+# CONFIG_EFI is not set
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_SOCKEV_NLMCAST=y
+CONFIG_CAN=y
+CONFIG_CAN_RH850=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+# CONFIG_BT_HS is not set
+# CONFIG_BT_LE is not set
+# CONFIG_BT_DEBUGFS is not set
+CONFIG_MSM_BT_POWER=y
+CONFIG_BTFM_SLIM=y
+CONFIG_BTFM_SLIM_WCN3990=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+# CONFIG_CFG80211_CRDA_SUPPORT is not set
+CONFIG_RFKILL=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_HDCP_QSEECOM=y
+CONFIG_PROFILER=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_E1000E=y
+CONFIG_MSM_RMNET_MHI=y
+CONFIG_RNDIS_IPA=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS_CRYPTO=y
+CONFIG_ATH_CARDS=y
+CONFIG_WIL6210=m
+CONFIG_CNSS=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y
+CONFIG_SECURE_TOUCH=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+# CONFIG_ACPI_I2C_OPREGION is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_PINCTRL_MSM8996=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_MSM_BCL_CTL=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_LIMITS_MONITOR=y
+CONFIG_LIMITS_LITE_HW=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_WCD9335_CODEC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_CPR3_HMSS=y
+CONFIG_REGULATOR_CPR3_MMSS=y
+CONFIG_REGULATOR_KRYO=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_PLATFORM=y
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_CAMERA_DEBUG=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI20_HEADER=y
+CONFIG_MSM_CSI22_HEADER=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSI31_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_EEPROM=y
+CONFIG_MSM_ISPIF=y
+CONFIG_IMX134=y
+CONFIG_IMX132=y
+CONFIG_OV9724=y
+CONFIG_OV5648=y
+CONFIG_GC0339=y
+CONFIG_OV8825=y
+CONFIG_OV8865=y
+CONFIG_s5k4e1=y
+CONFIG_OV12830=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_FD=y
+CONFIG_MSM_JPEGDMA=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_VMEM=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_QCOM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=m
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8996=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_QTI_KS_BRIDGE=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=4
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_ESOC=y
+CONFIG_ESOC_DEV=y
+CONFIG_ESOC_CLIENT=y
+CONFIG_ESOC_MDM_4x=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_BAM_DMA=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SW_SYNC_USER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_QPNP_REVID=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_GPIO_USB_DETECT=y
+CONFIG_MSM_MHI=y
+CONFIG_MSM_MHI_UCI=y
+CONFIG_SEEMP_CORE=y
+CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SMEM=y
+CONFIG_QPNP_HAPTIC=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
+CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_QCOM_SCM=y
+CONFIG_QCOM_SCM_XPU=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_BOOT_TIME_MARKER=y
+CONFIG_MSM_ADSP_LOADER=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_MPM_OF=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_QCOM_SMCINVOKE=y
+CONFIG_MSM_CACHE_M4M_ERP64=y
+CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE=y
+CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_QCOM_M4M_HWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
+CONFIG_DEVFREQ_SIMPLE_DEV=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_EXTCON=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_SENSORS_SSC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_IPC_LOGGING=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_DEBUG_ALIGN_RODATA=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_QPDI=y
+CONFIG_CORESIGHT_SOURCE_DUMMY=y
+CONFIG_PFK=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig
new file mode 100644 (file)
index 0000000..df5060e
--- /dev/null
@@ -0,0 +1,677 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8996=y
+CONFIG_PCI=y
+CONFIG_PCI_MSM=y
+CONFIG_ENABLE_FP_SIMD_SETTINGS=y
+CONFIG_MSM_APP_SETTINGS=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CMDLINE="console=ttyAMA0"
+# CONFIG_EFI is not set
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_SOCKEV_NLMCAST=y
+CONFIG_CAN=y
+CONFIG_CAN_RH850=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_BTFM_SLIM=y
+CONFIG_BTFM_SLIM_WCN3990=y
+CONFIG_CFG80211=y
+CONFIG_RFKILL=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_HDCP_QSEECOM=y
+CONFIG_PROFILER=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_E1000E=y
+CONFIG_MSM_RMNET_MHI=y
+CONFIG_RNDIS_IPA=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_USB_USBNET=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS_CRYPTO=y
+CONFIG_ATH_CARDS=y
+CONFIG_WIL6210=m
+CONFIG_CNSS=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=y
+CONFIG_SECURE_TOUCH=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+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_QUP=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_PINCTRL_MSM8996=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_MSM_BCL_CTL=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_LIMITS_MONITOR=y
+CONFIG_LIMITS_LITE_HW=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_WCD9335_CODEC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_CPR3_HMSS=y
+CONFIG_REGULATOR_CPR3_MMSS=y
+CONFIG_REGULATOR_KRYO=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_ADV_DEBUG=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_PLATFORM=y
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_CAMERA_DEBUG=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI20_HEADER=y
+CONFIG_MSM_CSI22_HEADER=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSI31_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_EEPROM=y
+CONFIG_MSM_ISPIF=y
+CONFIG_IMX134=y
+CONFIG_IMX132=y
+CONFIG_OV9724=y
+CONFIG_OV5648=y
+CONFIG_GC0339=y
+CONFIG_OV8825=y
+CONFIG_OV8865=y
+CONFIG_s5k4e1=y
+CONFIG_OV12830=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_FD=y
+CONFIG_MSM_JPEGDMA=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_VMEM=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_QCOM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=m
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8996=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_QTI_KS_BRIDGE=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SPI=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_EXYNOS=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_ESOC=y
+CONFIG_ESOC_DEV=y
+CONFIG_ESOC_CLIENT=y
+CONFIG_ESOC_DEBUG=y
+CONFIG_ESOC_MDM_4x=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_BAM_DMA=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SW_SYNC_USER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_QPNP_REVID=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_IPA_UT=y
+CONFIG_GPIO_USB_DETECT=y
+CONFIG_MSM_MHI=y
+CONFIG_MSM_MHI_UCI=y
+CONFIG_MSM_MHI_DEBUG=y
+CONFIG_SEEMP_CORE=y
+CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SMEM=y
+CONFIG_QPNP_HAPTIC=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
+CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_QCOM_SCM=y
+CONFIG_QCOM_SCM_XPU=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_BOOT_TIME_MARKER=y
+CONFIG_MSM_ADSP_LOADER=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_TRACER_PKT=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_MPM_OF=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_REMOTEQDSS=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_QCOM_SMCINVOKE=y
+CONFIG_MSM_CACHE_M4M_ERP64=y
+CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE=y
+CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_QCOM_M4M_HWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
+CONFIG_DEVFREQ_SIMPLE_DEV=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_EXTCON=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_PHY_XGENE=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_SENSORS_SSC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_PAGE_OWNER=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_UFS_FAULT_INJECTION=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_ARM64_PTDUMP=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_FREE_PAGES_RDONLY=y
+CONFIG_KERNEL_TEXT_RDONLY=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SOURCE_ETM4X=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_QPDI=y
+CONFIG_CORESIGHT_SOURCE_DUMMY=y
+CONFIG_PFK=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
+CONFIG_XZ_DEC=y
+CONFIG_QMI_ENCDEC=y
index a6413f1..3cd68ec 100644 (file)
@@ -519,6 +519,7 @@ CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
 CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
 CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_QCOM_SCM=y
 CONFIG_QCOM_SCM_XPU=y
 CONFIG_QCOM_WATCHDOG_V2=y
@@ -533,6 +534,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_TRACER_PKT=y
 CONFIG_MSM_MPM_OF=y
+CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_QBT1000=y
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
index 127a9d1..80e737e 100644 (file)
@@ -520,6 +520,7 @@ CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
 CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
 CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_QCOM_SCM=y
 CONFIG_QCOM_SCM_XPU=y
 CONFIG_QCOM_WATCHDOG_V2=y
@@ -535,6 +536,7 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_TRACER_PKT=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_MSM_MPM_OF=y
+CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_AVTIMER=y
 CONFIG_QCOM_REMOTEQDSS=y
 CONFIG_MSM_SERVICE_NOTIFIER=y
index 86b1143..a5c58dc 100644 (file)
@@ -274,6 +274,7 @@ CONFIG_BONDING=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
 CONFIG_SKY2=y
+CONFIG_MSM_RMNET_MHI=y
 CONFIG_RNDIS_IPA=y
 CONFIG_SMSC911X=y
 CONFIG_PPP=y
@@ -519,6 +520,8 @@ CONFIG_GSI=y
 CONFIG_IPA3=y
 CONFIG_RMNET_IPA3=y
 CONFIG_GPIO_USB_DETECT=y
+CONFIG_MSM_MHI=y
+CONFIG_MSM_MHI_UCI=y
 CONFIG_SEEMP_CORE=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_MDSS_PLL=y
index 25b6f6e..7a82377 100644 (file)
@@ -276,6 +276,7 @@ CONFIG_NETDEVICES=y
 CONFIG_BONDING=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
+CONFIG_MSM_RMNET_MHI=y
 CONFIG_RNDIS_IPA=y
 CONFIG_PPP=y
 CONFIG_PPP_BSDCOMP=y
@@ -531,6 +532,9 @@ CONFIG_GSI=y
 CONFIG_IPA3=y
 CONFIG_RMNET_IPA3=y
 CONFIG_GPIO_USB_DETECT=y
+CONFIG_MSM_MHI=y
+CONFIG_MSM_MHI_UCI=y
+CONFIG_MSM_MHI_DEBUG=y
 CONFIG_SEEMP_CORE=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_MDSS_PLL=y
index 3322f8f..28d900c 100644 (file)
@@ -4,6 +4,9 @@ CONFIG_AUDIT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_RCU_EXPERT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -242,7 +245,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
 CONFIG_HDCP_QSEECOM=y
-CONFIG_UID_CPUTIME=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_QPNP_MISC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
index 9a4841d..b75b424 100644 (file)
@@ -545,6 +545,7 @@ CONFIG_MSM_QMI_INTERFACE=y
 CONFIG_MSM_RPM_SMD=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_QCOM_DCC=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 CONFIG_MSM_SYSMON_GLINK_COMM=y
 CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
@@ -557,7 +558,6 @@ CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_ICNSS=y
 CONFIG_MSM_RUN_QUEUE_STATS=y
 CONFIG_MSM_BOOT_STATS=y
-CONFIG_QCOM_CPUSS_DUMP=y
 CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_CDSP_LOADER=y
 CONFIG_MSM_PERFORMANCE=y
index 13ae21b..3fe9e2b 100644 (file)
@@ -4,6 +4,9 @@ CONFIG_AUDIT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_RCU_EXPERT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -242,7 +245,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_QSEECOM=y
 CONFIG_HDCP_QSEECOM=y
-CONFIG_UID_CPUTIME=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_QPNP_MISC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -653,7 +656,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y
 CONFIG_DEBUG_OBJECTS_WORK=y
 CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
-CONFIG_SLUB_DEBUG_ON=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
diff --git a/arch/arm64/include/asm/app_api.h b/arch/arm64/include/asm/app_api.h
new file mode 100644 (file)
index 0000000..0e6a469
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_APP_API_H
+#define __ASM_APP_API_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+
+#define APP_SETTING_BIT                30
+#define MAX_ENTRIES            10
+
+/*
+ * APIs to set / clear the app setting bits
+ * in the register.
+ */
+#ifdef CONFIG_MSM_APP_API
+extern void set_app_setting_bit(uint32_t bit);
+extern void clear_app_setting_bit(uint32_t bit);
+extern void set_app_setting_bit_for_32bit_apps(void);
+extern void clear_app_setting_bit_for_32bit_apps(void);
+#else
+static inline void set_app_setting_bit(uint32_t bit) {}
+static inline void clear_app_setting_bit(uint32_t bit) {}
+static inline void set_app_setting_bit_for_32bit_apps(void) {}
+static inline void clear_app_setting_bit_for_32bit_apps(void) {}
+#endif
+
+#ifdef CONFIG_MSM_APP_SETTINGS
+extern void switch_app_setting_bit(struct task_struct *prev,
+                                  struct task_struct *next);
+extern void switch_32bit_app_setting_bit(struct task_struct *prev,
+                                  struct task_struct *next);
+extern void apply_app_setting_bit(struct file *file);
+extern bool use_app_setting;
+extern bool use_32bit_app_setting;
+extern bool use_32bit_app_setting_pro;
+#endif
+
+#endif
index 6150739..e77da20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013,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
@@ -15,7 +15,6 @@
 #define _ASM_DMA_CONTIGUOUS_H
 
 #ifdef __KERNEL__
-#ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
 
@@ -23,5 +22,3 @@ void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
 
 #endif
 #endif
-
-#endif
index ba8f19a..c16cf15 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/dma-debug.h>
 #include <linux/kmemcheck.h>
 #include <linux/kref.h>
-#include <linux/dma-mapping-fast.h>
 
 struct dma_iommu_mapping {
        /* iommu specific data */
@@ -21,8 +20,9 @@ struct dma_iommu_mapping {
 
        spinlock_t              lock;
        struct kref             kref;
-
+#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
        struct dma_fast_smmu_mapping *fast;
+#endif
 };
 
 #ifdef CONFIG_ARM64_DMA_USE_IOMMU
index 7875c88..a383c28 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include <asm/ptrace.h>
 #include <asm/user.h>
+#include <asm/fpsimd.h>
 
 /*
  * AArch64 static relocation types.
@@ -182,7 +183,11 @@ typedef compat_elf_greg_t          compat_elf_gregset_t[COMPAT_ELF_NGREG];
                                         ((x)->e_flags & EF_ARM_EABI_MASK))
 
 #define compat_start_thread            compat_start_thread
-#define COMPAT_SET_PERSONALITY(ex)     set_thread_flag(TIF_32BIT);
+#define COMPAT_SET_PERSONALITY(ex)                                     \
+do {                                                                   \
+       set_thread_flag(TIF_32BIT);                                     \
+} while (0)
+
 #define COMPAT_ARCH_DLINFO
 extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
                                      int uses_interp);
index 50f559f..3efaa5c 100644 (file)
@@ -81,6 +81,14 @@ extern void fpsimd_save_partial_state(struct fpsimd_partial_state *state,
                                      u32 num_regs);
 extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state);
 
+#ifdef CONFIG_ENABLE_FP_SIMD_SETTINGS
+extern void fpsimd_disable_trap(void);
+extern void fpsimd_enable_trap(void);
+#else
+static inline void fpsimd_disable_trap(void) {}
+static inline void fpsimd_enable_trap(void) {}
+#endif
+
 #endif
 
 #endif
index 69c203d..99f4410 100644 (file)
@@ -44,6 +44,8 @@ arm64-obj-$(CONFIG_PCI)                       += pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)   += armv8_deprecated.o
 arm64-obj-$(CONFIG_ACPI)               += acpi.o
 arm64-obj-$(CONFIG_RANDOMIZE_BASE)     += kaslr.o
+arm64-obj-$(CONFIG_MSM_APP_API)                += app_api.o
+arm64-obj-$(CONFIG_MSM_APP_SETTINGS)   += app_setting.o
 arm64-obj-$(CONFIG_HIBERNATION)                += hibernate.o hibernate-asm.o
 arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL)        += acpi_parking_protocol.o
 arm64-obj-$(CONFIG_PARAVIRT)           += paravirt.o
diff --git a/arch/arm64/kernel/app_api.c b/arch/arm64/kernel/app_api.c
new file mode 100644 (file)
index 0000000..e995bbf
--- /dev/null
@@ -0,0 +1,135 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <linux/export.h>
+
+#include <asm/app_api.h>
+
+static spinlock_t spinlock;
+static spinlock_t spinlock_32bit_app;
+static DEFINE_PER_CPU(int, app_config_applied);
+static unsigned long app_config_set[NR_CPUS];
+static unsigned long app_config_clear[NR_CPUS];
+
+void set_app_setting_bit(uint32_t bit)
+{
+       unsigned long flags;
+       uint64_t reg;
+       int cpu;
+
+       spin_lock_irqsave(&spinlock, flags);
+       asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg));
+       reg = reg | BIT(bit);
+       isb();
+       asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg));
+       isb();
+       if (bit == APP_SETTING_BIT) {
+               cpu = raw_smp_processor_id();
+               app_config_set[cpu]++;
+
+               this_cpu_write(app_config_applied, 1);
+       }
+       spin_unlock_irqrestore(&spinlock, flags);
+
+}
+EXPORT_SYMBOL(set_app_setting_bit);
+
+void clear_app_setting_bit(uint32_t bit)
+{
+       unsigned long flags;
+       uint64_t reg;
+       int cpu;
+
+       spin_lock_irqsave(&spinlock, flags);
+       asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg));
+       reg = reg & ~BIT(bit);
+       isb();
+       asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg));
+       isb();
+       if (bit == APP_SETTING_BIT) {
+               cpu = raw_smp_processor_id();
+               app_config_clear[cpu]++;
+
+               this_cpu_write(app_config_applied, 0);
+       }
+       spin_unlock_irqrestore(&spinlock, flags);
+}
+EXPORT_SYMBOL(clear_app_setting_bit);
+
+void set_app_setting_bit_for_32bit_apps(void)
+{
+       unsigned long flags;
+       uint64_t reg;
+
+       spin_lock_irqsave(&spinlock_32bit_app, flags);
+       if (use_32bit_app_setting) {
+               asm volatile("mrs %0, S3_0_c15_c15_0 " : "=r" (reg));
+               reg = reg | BIT(24);
+               isb();
+               asm volatile("msr S3_0_c15_c15_0, %0" : : "r" (reg));
+               isb();
+               asm volatile("mrs %0, S3_0_c15_c15_1 " : "=r" (reg));
+               reg = reg | BIT(18) | BIT(2) | BIT(0);
+               isb();
+               asm volatile("msr S3_0_c15_c15_1, %0" : : "r" (reg));
+               isb();
+       } else if (use_32bit_app_setting_pro) {
+               asm volatile("mrs %0, S3_0_c15_c15_1 " : "=r" (reg));
+               reg = reg | BIT(18);
+               isb();
+               asm volatile("msr S3_0_c15_c15_1, %0" : : "r" (reg));
+               isb();
+       }
+       spin_unlock_irqrestore(&spinlock_32bit_app, flags);
+}
+EXPORT_SYMBOL(set_app_setting_bit_for_32bit_apps);
+
+void clear_app_setting_bit_for_32bit_apps(void)
+{
+       unsigned long flags;
+       uint64_t reg;
+
+       spin_lock_irqsave(&spinlock_32bit_app, flags);
+       if (use_32bit_app_setting) {
+               asm volatile("mrs %0, S3_0_c15_c15_0 " : "=r" (reg));
+               reg = reg & ~BIT(24);
+               isb();
+               asm volatile("msr S3_0_c15_c15_0, %0" : : "r" (reg));
+               isb();
+               asm volatile("mrs %0, S3_0_c15_c15_1 " : "=r" (reg));
+               reg = reg & ~BIT(18);
+               reg = reg & ~BIT(2);
+               reg = reg & ~BIT(0);
+               isb();
+               asm volatile("msr S3_0_c15_c15_1, %0" : : "r" (reg));
+               isb();
+       } else if (use_32bit_app_setting_pro) {
+               asm volatile("mrs %0, S3_0_c15_c15_1 " : "=r" (reg));
+               reg = reg & ~BIT(18);
+               isb();
+               asm volatile("msr S3_0_c15_c15_1, %0" : : "r" (reg));
+               isb();
+       }
+       spin_unlock_irqrestore(&spinlock_32bit_app, flags);
+}
+EXPORT_SYMBOL(clear_app_setting_bit_for_32bit_apps);
+
+static int __init init_app_api(void)
+{
+       spin_lock_init(&spinlock);
+       spin_lock_init(&spinlock_32bit_app);
+       return 0;
+}
+early_initcall(init_app_api);
diff --git a/arch/arm64/kernel/app_setting.c b/arch/arm64/kernel/app_setting.c
new file mode 100644 (file)
index 0000000..0c6b003
--- /dev/null
@@ -0,0 +1,139 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+
+#include <asm/app_api.h>
+
+#define MAX_LEN                100
+
+static char *lib_names[MAX_ENTRIES];
+static unsigned int count;
+static struct mutex mutex;
+
+static char lib_str[MAX_LEN] = "";
+static struct kparam_string kps = {
+       .string                 = lib_str,
+       .maxlen                 = MAX_LEN,
+};
+static int set_name(const char *str, struct kernel_param *kp);
+module_param_call(lib_name, set_name, param_get_string, &kps, S_IWUSR);
+
+bool use_app_setting = true;
+module_param(use_app_setting, bool, 0644);
+MODULE_PARM_DESC(use_app_setting, "control use of app specific settings");
+
+bool use_32bit_app_setting = true;
+module_param(use_32bit_app_setting, bool, 0644);
+MODULE_PARM_DESC(use_32bit_app_setting, "control use of 32 bit app specific settings");
+
+bool use_32bit_app_setting_pro;
+module_param(use_32bit_app_setting_pro, bool, 0644);
+MODULE_PARM_DESC(use_32bit_app_setting_pro, "control use of 32 bit app specific settings");
+
+static int set_name(const char *str, struct kernel_param *kp)
+{
+       int len = strlen(str);
+       char *name;
+
+       if (len >= MAX_LEN) {
+               pr_err("app_setting: name string too long\n");
+               return -ENOSPC;
+       }
+
+       /*
+        * echo adds '\n' which we need to chop off later
+        */
+       name = kzalloc(len + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       strlcpy(name, str, len + 1);
+
+       if (name[len - 1] == '\n')
+               name[len - 1] = '\0';
+
+       mutex_lock(&mutex);
+       if (count < MAX_ENTRIES) {
+               lib_names[count] = name;
+               /*
+                * mb to ensure that the new lib_names entry is present
+                * before updating the view presented by get_lib_names
+                */
+               mb();
+               count++;
+       } else {
+               pr_err("app_setting: set name failed. Max entries reached\n");
+               kfree(name);
+               mutex_unlock(&mutex);
+               return -EPERM;
+       }
+       mutex_unlock(&mutex);
+
+       return 0;
+}
+
+void switch_app_setting_bit(struct task_struct *prev, struct task_struct *next)
+{
+       if (prev->mm && unlikely(prev->mm->app_setting))
+               clear_app_setting_bit(APP_SETTING_BIT);
+
+       if (next->mm && unlikely(next->mm->app_setting))
+               set_app_setting_bit(APP_SETTING_BIT);
+}
+EXPORT_SYMBOL(switch_app_setting_bit);
+
+void switch_32bit_app_setting_bit(struct task_struct *prev,
+                                       struct task_struct *next)
+{
+       if (prev->mm && unlikely(is_compat_thread(task_thread_info(prev))))
+               clear_app_setting_bit_for_32bit_apps();
+
+       if (next->mm && unlikely(is_compat_thread(task_thread_info(next))))
+               set_app_setting_bit_for_32bit_apps();
+}
+EXPORT_SYMBOL(switch_32bit_app_setting_bit);
+
+void apply_app_setting_bit(struct file *file)
+{
+       bool found = false;
+       int i;
+
+       if (file && file->f_path.dentry) {
+               const char *name = file->f_path.dentry->d_name.name;
+
+               for (i = 0; i < count; i++) {
+                       if (unlikely(!strcmp(name, lib_names[i]))) {
+                               found = true;
+                               break;
+                       }
+               }
+               if (found) {
+                       preempt_disable();
+                       set_app_setting_bit(APP_SETTING_BIT);
+                       /* This will take care of child processes as well */
+                       current->mm->app_setting = 1;
+                       preempt_enable();
+               }
+       }
+}
+EXPORT_SYMBOL(apply_app_setting_bit);
+
+static int __init app_setting_init(void)
+{
+       mutex_init(&mutex);
+       return 0;
+}
+module_init(app_setting_init);
index c44a82f..1ffe154 100644 (file)
@@ -64,4 +64,20 @@ ENTRY(fpsimd_load_partial_state)
        ret
 ENDPROC(fpsimd_load_partial_state)
 
+#ifdef CONFIG_ENABLE_FP_SIMD_SETTINGS
+ENTRY(fpsimd_enable_trap)
+       mrs x0, cpacr_el1
+       bic x0, x0, #(3 << 20)
+       orr x0, x0, #(1 << 20)
+       msr cpacr_el1, x0
+       ret
+ENDPROC(fpsimd_enable_trap)
+ENTRY(fpsimd_disable_trap)
+       mrs x0, cpacr_el1
+       orr x0, x0, #(3 << 20)
+       msr cpacr_el1, x0
+       ret
+ENDPROC(fpsimd_disable_trap)
+#endif
+
 #endif
index 191e313..0ea6530 100644 (file)
@@ -561,7 +561,7 @@ el0_sync_compat:
        cmp     x24, #ESR_ELx_EC_IABT_LOW       // instruction abort in EL0
        b.eq    el0_ia
        cmp     x24, #ESR_ELx_EC_FP_ASIMD       // FP/ASIMD access
-       b.eq    el0_fpsimd_acc
+       b.eq    el0_fpsimd_acc_compat
        cmp     x24, #ESR_ELx_EC_FP_EXC32       // FP/ASIMD exception
        b.eq    el0_fpsimd_exc
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
@@ -632,6 +632,17 @@ el0_fpsimd_acc:
        mov     x1, sp
        bl      do_fpsimd_acc
        b       ret_to_user
+el0_fpsimd_acc_compat:
+       /*
+        * Floating Point or Advanced SIMD access
+        */
+       enable_dbg
+       ct_user_exit
+       mov     x0, x25
+       mov     x1, sp
+       bl      do_fpsimd_acc_compat
+       b       ret_to_user
+
 el0_fpsimd_exc:
        /*
         * Floating Point or Advanced SIMD exception
index acc1afd..790d27e 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/cpu.h>
 #include <linux/cpu_pm.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -27,6 +28,7 @@
 
 #include <asm/fpsimd.h>
 #include <asm/cputype.h>
+#include <asm/app_api.h>
 
 #define FPEXC_IOF      (1 << 0)
 #define FPEXC_DZF      (1 << 1)
@@ -35,6 +37,8 @@
 #define FPEXC_IXF      (1 << 4)
 #define FPEXC_IDF      (1 << 7)
 
+#define FP_SIMD_BIT    31
+
 /*
  * In order to reduce the number of times the FPSIMD state is needlessly saved
  * and restored, we need to keep track of two things:
  *   whatever is in the FPSIMD registers is not saved to memory, but discarded.
  */
 static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state);
+static DEFINE_PER_CPU(int, fpsimd_stg_enable);
+
+static int fpsimd_settings = 0x1; /* default = 0x1 */
+module_param(fpsimd_settings, int, 0644);
+
+void fpsimd_settings_enable(void)
+{
+       set_app_setting_bit(FP_SIMD_BIT);
+}
+
+void fpsimd_settings_disable(void)
+{
+       clear_app_setting_bit(FP_SIMD_BIT);
+}
 
 /*
  * Trapped FP/ASIMD access.
  */
 void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
 {
-       /* TODO: implement lazy context saving/restoring */
-       WARN_ON(1);
+       if (!fpsimd_settings)
+               return;
+
+       fpsimd_disable_trap();
+       fpsimd_settings_disable();
+       this_cpu_write(fpsimd_stg_enable, 0);
+}
+
+void do_fpsimd_acc_compat(unsigned int esr, struct pt_regs *regs)
+{
+       if (!fpsimd_settings)
+               return;
+
+       fpsimd_disable_trap();
+       fpsimd_settings_enable();
+       this_cpu_write(fpsimd_stg_enable, 1);
 }
 
 /*
@@ -135,6 +167,11 @@ void fpsimd_thread_switch(struct task_struct *next)
        if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
                fpsimd_save_state(&current->thread.fpsimd_state);
 
+       if (fpsimd_settings && __this_cpu_read(fpsimd_stg_enable)) {
+               fpsimd_settings_disable();
+               this_cpu_write(fpsimd_stg_enable, 0);
+       }
+
        if (next->mm) {
                /*
                 * If we are switching to a task whose most recent userland
@@ -152,6 +189,14 @@ void fpsimd_thread_switch(struct task_struct *next)
                else
                        set_ti_thread_flag(task_thread_info(next),
                                           TIF_FOREIGN_FPSTATE);
+
+               if (!fpsimd_settings)
+                       return;
+
+               if (test_ti_thread_flag(task_thread_info(next), TIF_32BIT))
+                       fpsimd_enable_trap();
+               else
+                       fpsimd_disable_trap();
        }
 }
 
index c2bf5a5..9a3aec9 100644 (file)
@@ -132,6 +132,11 @@ ENTRY(_cpu_resume)
         */
        bl      cpu_do_resume
 
+#ifdef CONFIG_KASAN
+       mov     x0, sp
+       bl      kasan_unpoison_remaining_stack
+#endif
+
        ldp     x19, x20, [x29, #16]
        ldp     x21, x22, [x29, #32]
        ldp     x23, x24, [x29, #48]
index 273e612..07238b3 100644 (file)
@@ -197,20 +197,21 @@ extern long __must_check strnlen_user(const char __user *src, long count);
 
 #define strlen_user(str) strnlen_user(str, 32767)
 
-extern unsigned long __must_check __copy_user_zeroing(void *to,
-                                                     const void __user *from,
-                                                     unsigned long n);
+extern unsigned long raw_copy_from_user(void *to, const void __user *from,
+                                       unsigned long n);
 
 static inline unsigned long
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
+       unsigned long res = n;
        if (likely(access_ok(VERIFY_READ, from, n)))
-               return __copy_user_zeroing(to, from, n);
-       memset(to, 0, n);
-       return n;
+               res = raw_copy_from_user(to, from, n);
+       if (unlikely(res))
+               memset(to + (n - res), 0, res);
+       return res;
 }
 
-#define __copy_from_user(to, from, n) __copy_user_zeroing(to, from, n)
+#define __copy_from_user(to, from, n) raw_copy_from_user(to, from, n)
 #define __copy_from_user_inatomic __copy_from_user
 
 extern unsigned long __must_check __copy_user(void __user *to,
index b3ebfe9..2792fc6 100644 (file)
@@ -29,7 +29,6 @@
                COPY                                             \
                "1:\n"                                           \
                "       .section .fixup,\"ax\"\n"                \
-               "       MOV D1Ar1,#0\n"                          \
                FIXUP                                            \
                "       MOVT    D1Ar1,#HI(1b)\n"                 \
                "       JUMP    D1Ar1,#LO(1b)\n"                 \
                "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
                "22:\n"                                                 \
                "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
-               "SUB    %3, %3, #32\n"                                  \
                "23:\n"                                                 \
-               "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
+               "SUB    %3, %3, #32\n"                                  \
                "24:\n"                                                 \
+               "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
+               "25:\n"                                                 \
                "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "26:\n"                                                 \
                "SUB    %3, %3, #32\n"                                  \
                "DCACHE [%1+#-64], D0Ar6\n"                             \
                "BR     $Lloop"id"\n"                                   \
                                                                        \
                "MOV    RAPF, %1\n"                                     \
-               "25:\n"                                                 \
+               "27:\n"                                                 \
                "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "26:\n"                                                 \
+               "28:\n"                                                 \
                "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "29:\n"                                                 \
                "SUB    %3, %3, #32\n"                                  \
-               "27:\n"                                                 \
+               "30:\n"                                                 \
                "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "28:\n"                                                 \
+               "31:\n"                                                 \
                "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "32:\n"                                                 \
                "SUB    %0, %0, #8\n"                                   \
-               "29:\n"                                                 \
+               "33:\n"                                                 \
                "SETL   [%0++], D0.7, D1.7\n"                           \
                "SUB    %3, %3, #32\n"                                  \
                "1:"                                                    \
                "       .long 26b,3b\n"                                 \
                "       .long 27b,3b\n"                                 \
                "       .long 28b,3b\n"                                 \
-               "       .long 29b,4b\n"                                 \
+               "       .long 29b,3b\n"                                 \
+               "       .long 30b,3b\n"                                 \
+               "       .long 31b,3b\n"                                 \
+               "       .long 32b,3b\n"                                 \
+               "       .long 33b,4b\n"                                 \
                "       .previous\n"                                    \
                : "=r" (to), "=r" (from), "=r" (ret), "=d" (n)          \
                : "0" (to), "1" (from), "2" (ret), "3" (n)              \
-               : "D1Ar1", "D0Ar2", "memory")
+               : "D1Ar1", "D0Ar2", "cc", "memory")
 
 /*     rewind 'to' and 'from'  pointers when a fault occurs
  *
 #define __asm_copy_to_user_64bit_rapf_loop(to, from, ret, n, id)\
        __asm_copy_user_64bit_rapf_loop(to, from, ret, n, id,           \
                "LSR    D0Ar2, D0Ar2, #8\n"                             \
-               "AND    D0Ar2, D0Ar2, #0x7\n"                           \
+               "ANDS   D0Ar2, D0Ar2, #0x7\n"                           \
                "ADDZ   D0Ar2, D0Ar2, #4\n"                             \
                "SUB    D0Ar2, D0Ar2, #1\n"                             \
                "MOV    D1Ar1, #4\n"                                    \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
                "22:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
-               "SUB    %3, %3, #16\n"                                  \
                "23:\n"                                                 \
-               "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "24:\n"                                                 \
-               "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
                "SUB    %3, %3, #16\n"                                  \
-               "25:\n"                                                 \
+               "24:\n"                                                 \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "26:\n"                                                 \
+               "25:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "26:\n"                                                 \
                "SUB    %3, %3, #16\n"                                  \
                "27:\n"                                                 \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
                "28:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "29:\n"                                                 \
+               "SUB    %3, %3, #16\n"                                  \
+               "30:\n"                                                 \
+               "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
+               "31:\n"                                                 \
+               "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "32:\n"                                                 \
                "SUB    %3, %3, #16\n"                                  \
                "DCACHE [%1+#-64], D0Ar6\n"                             \
                "BR     $Lloop"id"\n"                                   \
                                                                        \
                "MOV    RAPF, %1\n"                                     \
-               "29:\n"                                                 \
+               "33:\n"                                                 \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "30:\n"                                                 \
+               "34:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "35:\n"                                                 \
                "SUB    %3, %3, #16\n"                                  \
-               "31:\n"                                                 \
+               "36:\n"                                                 \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "32:\n"                                                 \
+               "37:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "38:\n"                                                 \
                "SUB    %3, %3, #16\n"                                  \
-               "33:\n"                                                 \
+               "39:\n"                                                 \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "34:\n"                                                 \
+               "40:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "41:\n"                                                 \
                "SUB    %3, %3, #16\n"                                  \
-               "35:\n"                                                 \
+               "42:\n"                                                 \
                "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
-               "36:\n"                                                 \
+               "43:\n"                                                 \
                "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
+               "44:\n"                                                 \
                "SUB    %0, %0, #4\n"                                   \
-               "37:\n"                                                 \
+               "45:\n"                                                 \
                "SETD   [%0++], D0.7\n"                                 \
                "SUB    %3, %3, #16\n"                                  \
                "1:"                                                    \
                "       .long 34b,3b\n"                                 \
                "       .long 35b,3b\n"                                 \
                "       .long 36b,3b\n"                                 \
-               "       .long 37b,4b\n"                                 \
+               "       .long 37b,3b\n"                                 \
+               "       .long 38b,3b\n"                                 \
+               "       .long 39b,3b\n"                                 \
+               "       .long 40b,3b\n"                                 \
+               "       .long 41b,3b\n"                                 \
+               "       .long 42b,3b\n"                                 \
+               "       .long 43b,3b\n"                                 \
+               "       .long 44b,3b\n"                                 \
+               "       .long 45b,4b\n"                                 \
                "       .previous\n"                                    \
                : "=r" (to), "=r" (from), "=r" (ret), "=d" (n)          \
                : "0" (to), "1" (from), "2" (ret), "3" (n)              \
-               : "D1Ar1", "D0Ar2", "memory")
+               : "D1Ar1", "D0Ar2", "cc", "memory")
 
 /*     rewind 'to' and 'from'  pointers when a fault occurs
  *
 #define __asm_copy_to_user_32bit_rapf_loop(to, from, ret, n, id)\
        __asm_copy_user_32bit_rapf_loop(to, from, ret, n, id,           \
                "LSR    D0Ar2, D0Ar2, #8\n"                             \
-               "AND    D0Ar2, D0Ar2, #0x7\n"                           \
+               "ANDS   D0Ar2, D0Ar2, #0x7\n"                           \
                "ADDZ   D0Ar2, D0Ar2, #4\n"                             \
                "SUB    D0Ar2, D0Ar2, #1\n"                             \
                "MOV    D1Ar1, #4\n"                                    \
@@ -538,23 +561,31 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
        if ((unsigned long) src & 1) {
                __asm_copy_to_user_1(dst, src, retn);
                n--;
+               if (retn)
+                       return retn + n;
        }
        if ((unsigned long) dst & 1) {
                /* Worst case - byte copy */
                while (n > 0) {
                        __asm_copy_to_user_1(dst, src, retn);
                        n--;
+                       if (retn)
+                               return retn + n;
                }
        }
        if (((unsigned long) src & 2) && n >= 2) {
                __asm_copy_to_user_2(dst, src, retn);
                n -= 2;
+               if (retn)
+                       return retn + n;
        }
        if ((unsigned long) dst & 2) {
                /* Second worst case - word copy */
                while (n >= 2) {
                        __asm_copy_to_user_2(dst, src, retn);
                        n -= 2;
+                       if (retn)
+                               return retn + n;
                }
        }
 
@@ -569,6 +600,8 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
                while (n >= 8) {
                        __asm_copy_to_user_8x64(dst, src, retn);
                        n -= 8;
+                       if (retn)
+                               return retn + n;
                }
        }
        if (n >= RAPF_MIN_BUF_SIZE) {
@@ -581,6 +614,8 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
                while (n >= 8) {
                        __asm_copy_to_user_8x64(dst, src, retn);
                        n -= 8;
+                       if (retn)
+                               return retn + n;
                }
        }
 #endif
@@ -588,11 +623,15 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
        while (n >= 16) {
                __asm_copy_to_user_16(dst, src, retn);
                n -= 16;
+               if (retn)
+                       return retn + n;
        }
 
        while (n >= 4) {
                __asm_copy_to_user_4(dst, src, retn);
                n -= 4;
+               if (retn)
+                       return retn + n;
        }
 
        switch (n) {
@@ -609,6 +648,10 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
                break;
        }
 
+       /*
+        * If we get here, retn correctly reflects the number of failing
+        * bytes.
+        */
        return retn;
 }
 EXPORT_SYMBOL(__copy_user);
@@ -617,16 +660,14 @@ EXPORT_SYMBOL(__copy_user);
        __asm_copy_user_cont(to, from, ret,     \
                "       GETB D1Ar1,[%1++]\n"    \
                "2:     SETB [%0++],D1Ar1\n",   \
-               "3:     ADD  %2,%2,#1\n"        \
-               "       SETB [%0++],D1Ar1\n",   \
+               "3:     ADD  %2,%2,#1\n",       \
                "       .long 2b,3b\n")
 
 #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
        __asm_copy_user_cont(to, from, ret,             \
                "       GETW D1Ar1,[%1++]\n"            \
                "2:     SETW [%0++],D1Ar1\n" COPY,      \
-               "3:     ADD  %2,%2,#2\n"                \
-               "       SETW [%0++],D1Ar1\n" FIXUP,     \
+               "3:     ADD  %2,%2,#2\n" FIXUP,         \
                "       .long 2b,3b\n" TENTRY)
 
 #define __asm_copy_from_user_2(to, from, ret) \
@@ -636,145 +677,26 @@ EXPORT_SYMBOL(__copy_user);
        __asm_copy_from_user_2x_cont(to, from, ret,     \
                "       GETB D1Ar1,[%1++]\n"            \
                "4:     SETB [%0++],D1Ar1\n",           \
-               "5:     ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
+               "5:     ADD  %2,%2,#1\n",               \
                "       .long 4b,5b\n")
 
 #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
        __asm_copy_user_cont(to, from, ret,             \
                "       GETD D1Ar1,[%1++]\n"            \
                "2:     SETD [%0++],D1Ar1\n" COPY,      \
-               "3:     ADD  %2,%2,#4\n"                \
-               "       SETD [%0++],D1Ar1\n" FIXUP,     \
+               "3:     ADD  %2,%2,#4\n" FIXUP,         \
                "       .long 2b,3b\n" TENTRY)
 
 #define __asm_copy_from_user_4(to, from, ret) \
        __asm_copy_from_user_4x_cont(to, from, ret, "", "", "")
 
-#define __asm_copy_from_user_5(to, from, ret) \
-       __asm_copy_from_user_4x_cont(to, from, ret,     \
-               "       GETB D1Ar1,[%1++]\n"            \
-               "4:     SETB [%0++],D1Ar1\n",           \
-               "5:     ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
-               "       .long 4b,5b\n")
-
-#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-       __asm_copy_from_user_4x_cont(to, from, ret,     \
-               "       GETW D1Ar1,[%1++]\n"            \
-               "4:     SETW [%0++],D1Ar1\n" COPY,      \
-               "5:     ADD  %2,%2,#2\n"                \
-               "       SETW [%0++],D1Ar1\n" FIXUP,     \
-               "       .long 4b,5b\n" TENTRY)
-
-#define __asm_copy_from_user_6(to, from, ret) \
-       __asm_copy_from_user_6x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_7(to, from, ret) \
-       __asm_copy_from_user_6x_cont(to, from, ret,     \
-               "       GETB D1Ar1,[%1++]\n"            \
-               "6:     SETB [%0++],D1Ar1\n",           \
-               "7:     ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
-               "       .long 6b,7b\n")
-
-#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-       __asm_copy_from_user_4x_cont(to, from, ret,     \
-               "       GETD D1Ar1,[%1++]\n"            \
-               "4:     SETD [%0++],D1Ar1\n" COPY,      \
-               "5:     ADD  %2,%2,#4\n"                        \
-               "       SETD [%0++],D1Ar1\n" FIXUP,             \
-               "       .long 4b,5b\n" TENTRY)
-
-#define __asm_copy_from_user_8(to, from, ret) \
-       __asm_copy_from_user_8x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_9(to, from, ret) \
-       __asm_copy_from_user_8x_cont(to, from, ret,     \
-               "       GETB D1Ar1,[%1++]\n"            \
-               "6:     SETB [%0++],D1Ar1\n",           \
-               "7:     ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
-               "       .long 6b,7b\n")
-
-#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-       __asm_copy_from_user_8x_cont(to, from, ret,     \
-               "       GETW D1Ar1,[%1++]\n"            \
-               "6:     SETW [%0++],D1Ar1\n" COPY,      \
-               "7:     ADD  %2,%2,#2\n"                \
-               "       SETW [%0++],D1Ar1\n" FIXUP,     \
-               "       .long 6b,7b\n" TENTRY)
-
-#define __asm_copy_from_user_10(to, from, ret) \
-       __asm_copy_from_user_10x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_11(to, from, ret)         \
-       __asm_copy_from_user_10x_cont(to, from, ret,    \
-               "       GETB D1Ar1,[%1++]\n"            \
-               "8:     SETB [%0++],D1Ar1\n",           \
-               "9:     ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
-               "       .long 8b,9b\n")
-
-#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-       __asm_copy_from_user_8x_cont(to, from, ret,     \
-               "       GETD D1Ar1,[%1++]\n"            \
-               "6:     SETD [%0++],D1Ar1\n" COPY,      \
-               "7:     ADD  %2,%2,#4\n"                \
-               "       SETD [%0++],D1Ar1\n" FIXUP,     \
-               "       .long 6b,7b\n" TENTRY)
-
-#define __asm_copy_from_user_12(to, from, ret) \
-       __asm_copy_from_user_12x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_13(to, from, ret) \
-       __asm_copy_from_user_12x_cont(to, from, ret,    \
-               "       GETB D1Ar1,[%1++]\n"            \
-               "8:     SETB [%0++],D1Ar1\n",           \
-               "9:     ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
-               "       .long 8b,9b\n")
-
-#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-       __asm_copy_from_user_12x_cont(to, from, ret,    \
-               "       GETW D1Ar1,[%1++]\n"            \
-               "8:     SETW [%0++],D1Ar1\n" COPY,      \
-               "9:     ADD  %2,%2,#2\n"                \
-               "       SETW [%0++],D1Ar1\n" FIXUP,     \
-               "       .long 8b,9b\n" TENTRY)
-
-#define __asm_copy_from_user_14(to, from, ret) \
-       __asm_copy_from_user_14x_cont(to, from, ret, "", "", "")
-
-#define __asm_copy_from_user_15(to, from, ret) \
-       __asm_copy_from_user_14x_cont(to, from, ret,    \
-               "       GETB D1Ar1,[%1++]\n"            \
-               "10:    SETB [%0++],D1Ar1\n",           \
-               "11:    ADD  %2,%2,#1\n"                \
-               "       SETB [%0++],D1Ar1\n",           \
-               "       .long 10b,11b\n")
-
-#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
-       __asm_copy_from_user_12x_cont(to, from, ret,    \
-               "       GETD D1Ar1,[%1++]\n"            \
-               "8:     SETD [%0++],D1Ar1\n" COPY,      \
-               "9:     ADD  %2,%2,#4\n"                \
-               "       SETD [%0++],D1Ar1\n" FIXUP,     \
-               "       .long 8b,9b\n" TENTRY)
-
-#define __asm_copy_from_user_16(to, from, ret) \
-       __asm_copy_from_user_16x_cont(to, from, ret, "", "", "")
-
 #define __asm_copy_from_user_8x64(to, from, ret) \
        asm volatile (                          \
                "       GETL D0Ar2,D1Ar1,[%1++]\n"      \
                "2:     SETL [%0++],D0Ar2,D1Ar1\n"      \
                "1:\n"                                  \
                "       .section .fixup,\"ax\"\n"       \
-               "       MOV D1Ar1,#0\n"                 \
-               "       MOV D0Ar2,#0\n"                 \
                "3:     ADD  %2,%2,#8\n"                \
-               "       SETL [%0++],D0Ar2,D1Ar1\n"      \
                "       MOVT    D0Ar2,#HI(1b)\n"        \
                "       JUMP    D0Ar2,#LO(1b)\n"        \
                "       .previous\n"                    \
@@ -789,36 +711,57 @@ EXPORT_SYMBOL(__copy_user);
  *
  *     Rationale:
  *             A fault occurs while reading from user buffer, which is the
- *             source. Since the fault is at a single address, we only
- *             need to rewind by 8 bytes.
+ *             source.
  *             Since we don't write to kernel buffer until we read first,
  *             the kernel buffer is at the right state and needn't be
- *             corrected.
+ *             corrected, but the source must be rewound to the beginning of
+ *             the block, which is LSM_STEP*8 bytes.
+ *             LSM_STEP is bits 10:8 in TXSTATUS which is already read
+ *             and stored in D0Ar2
+ *
+ *             NOTE: If a fault occurs at the last operation in M{G,S}ETL
+ *                     LSM_STEP will be 0. ie: we do 4 writes in our case, if
+ *                     a fault happens at the 4th write, LSM_STEP will be 0
+ *                     instead of 4. The code copes with that.
  */
 #define __asm_copy_from_user_64bit_rapf_loop(to, from, ret, n, id)     \
        __asm_copy_user_64bit_rapf_loop(to, from, ret, n, id,           \
-               "SUB    %1, %1, #8\n")
+               "LSR    D0Ar2, D0Ar2, #5\n"                             \
+               "ANDS   D0Ar2, D0Ar2, #0x38\n"                          \
+               "ADDZ   D0Ar2, D0Ar2, #32\n"                            \
+               "SUB    %1, %1, D0Ar2\n")
 
 /*     rewind 'from' pointer when a fault occurs
  *
  *     Rationale:
  *             A fault occurs while reading from user buffer, which is the
- *             source. Since the fault is at a single address, we only
- *             need to rewind by 4 bytes.
+ *             source.
  *             Since we don't write to kernel buffer until we read first,
  *             the kernel buffer is at the right state and needn't be
- *             corrected.
+ *             corrected, but the source must be rewound to the beginning of
+ *             the block, which is LSM_STEP*4 bytes.
+ *             LSM_STEP is bits 10:8 in TXSTATUS which is already read
+ *             and stored in D0Ar2
+ *
+ *             NOTE: If a fault occurs at the last operation in M{G,S}ETL
+ *                     LSM_STEP will be 0. ie: we do 4 writes in our case, if
+ *                     a fault happens at the 4th write, LSM_STEP will be 0
+ *                     instead of 4. The code copes with that.
  */
 #define __asm_copy_from_user_32bit_rapf_loop(to, from, ret, n, id)     \
        __asm_copy_user_32bit_rapf_loop(to, from, ret, n, id,           \
-               "SUB    %1, %1, #4\n")
+               "LSR    D0Ar2, D0Ar2, #6\n"                             \
+               "ANDS   D0Ar2, D0Ar2, #0x1c\n"                          \
+               "ADDZ   D0Ar2, D0Ar2, #16\n"                            \
+               "SUB    %1, %1, D0Ar2\n")
 
 
-/* Copy from user to kernel, zeroing the bytes that were inaccessible in
-   userland.  The return-value is the number of bytes that were
-   inaccessible.  */
-unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
-                                 unsigned long n)
+/*
+ * Copy from user to kernel. The return-value is the number of bytes that were
+ * inaccessible.
+ */
+unsigned long raw_copy_from_user(void *pdst, const void __user *psrc,
+                                unsigned long n)
 {
        register char *dst asm ("A0.2") = pdst;
        register const char __user *src asm ("A1.2") = psrc;
@@ -830,6 +773,8 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
        if ((unsigned long) src & 1) {
                __asm_copy_from_user_1(dst, src, retn);
                n--;
+               if (retn)
+                       return retn + n;
        }
        if ((unsigned long) dst & 1) {
                /* Worst case - byte copy */
@@ -837,12 +782,14 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
                        __asm_copy_from_user_1(dst, src, retn);
                        n--;
                        if (retn)
-                               goto copy_exception_bytes;
+                               return retn + n;
                }
        }
        if (((unsigned long) src & 2) && n >= 2) {
                __asm_copy_from_user_2(dst, src, retn);
                n -= 2;
+               if (retn)
+                       return retn + n;
        }
        if ((unsigned long) dst & 2) {
                /* Second worst case - word copy */
@@ -850,16 +797,10 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
                        __asm_copy_from_user_2(dst, src, retn);
                        n -= 2;
                        if (retn)
-                               goto copy_exception_bytes;
+                               return retn + n;
                }
        }
 
-       /* We only need one check after the unalignment-adjustments,
-          because if both adjustments were done, either both or
-          neither reference had an exception.  */
-       if (retn != 0)
-               goto copy_exception_bytes;
-
 #ifdef USE_RAPF
        /* 64 bit copy loop */
        if (!(((unsigned long) src | (unsigned long) dst) & 7)) {
@@ -872,7 +813,7 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
                        __asm_copy_from_user_8x64(dst, src, retn);
                        n -= 8;
                        if (retn)
-                               goto copy_exception_bytes;
+                               return retn + n;
                }
        }
 
@@ -888,7 +829,7 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
                        __asm_copy_from_user_8x64(dst, src, retn);
                        n -= 8;
                        if (retn)
-                               goto copy_exception_bytes;
+                               return retn + n;
                }
        }
 #endif
@@ -898,7 +839,7 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
                n -= 4;
 
                if (retn)
-                       goto copy_exception_bytes;
+                       return retn + n;
        }
 
        /* If we get here, there were no memory read faults.  */
@@ -924,21 +865,8 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
        /* If we get here, retn correctly reflects the number of failing
           bytes.  */
        return retn;
-
- copy_exception_bytes:
-       /* We already have "retn" bytes cleared, and need to clear the
-          remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
-          memset is preferred here, since this isn't speed-critical code and
-          we'd rather have this a leaf-function than calling memset.  */
-       {
-               char *endp;
-               for (endp = dst + n; dst < endp; dst++)
-                       *dst = 0;
-       }
-
-       return retn + n;
 }
-EXPORT_SYMBOL(__copy_user_zeroing);
+EXPORT_SYMBOL(raw_copy_from_user);
 
 #define __asm_clear_8x64(to, ret) \
        asm volatile (                                  \
index db45961..8b0424a 100644 (file)
@@ -9,6 +9,7 @@ config MIPS
        select HAVE_CONTEXT_TRACKING
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IDE
+       select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
@@ -1463,7 +1464,7 @@ config CPU_MIPS64_R6
        select CPU_SUPPORTS_HIGHMEM
        select CPU_SUPPORTS_MSA
        select GENERIC_CSUM
-       select MIPS_O32_FP64_SUPPORT if MIPS32_O32
+       select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32
        help
          Choose this option to build a kernel for release 6 or later of the
          MIPS64 architecture.  New MIPS processors, starting with the Warrior
index 15e0fec..ebb9efb 100644 (file)
 
 #include <irq.h>
 
+#define IRQ_STACK_SIZE                 THREAD_SIZE
+
+extern void *irq_stack[NR_CPUS];
+
+static inline bool on_irq_stack(int cpu, unsigned long sp)
+{
+       unsigned long low = (unsigned long)irq_stack[cpu];
+       unsigned long high = low + IRQ_STACK_SIZE;
+
+       return (low <= sp && sp <= high);
+}
+
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
index 40196be..2365ce0 100644 (file)
@@ -112,7 +112,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
                "       andi    %[ticket], %[ticket], 0xffff            \n"
                "       bne     %[ticket], %[my_ticket], 4f             \n"
                "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "2:                                                     \n"
+               "2:     .insn                                           \n"
                "       .subsection 2                                   \n"
                "4:     andi    %[ticket], %[ticket], 0xffff            \n"
                "       sll     %[ticket], 5                            \n"
@@ -187,7 +187,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
                "       sc      %[ticket], %[ticket_ptr]                \n"
                "       beqz    %[ticket], 1b                           \n"
                "        li     %[ticket], 1                            \n"
-               "2:                                                     \n"
+               "2:     .insn                                           \n"
                "       .subsection 2                                   \n"
                "3:     b       2b                                      \n"
                "        li     %[ticket], 0                            \n"
@@ -367,7 +367,7 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
                "       .set    reorder                                 \n"
                __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
-               "2:                                                     \n"
+               "2:     .insn                                           \n"
                : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
                : GCC_OFF_SMALL_ASM() (rw->lock)
                : "memory");
@@ -407,7 +407,7 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
                        "       lui     %1, 0x8000                      \n"
                        "       sc      %1, %0                          \n"
                        "       li      %2, 1                           \n"
-                       "2:                                             \n"
+                       "2:     .insn                                   \n"
                        : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp),
                          "=&r" (ret)
                        : GCC_OFF_SMALL_ASM() (rw->lock)
index a71da57..5347f13 100644 (file)
                LONG_S  $25, PT_R25(sp)
                LONG_S  $28, PT_R28(sp)
                LONG_S  $31, PT_R31(sp)
+
+               /* Set thread_info if we're coming from user mode */
+               mfc0    k0, CP0_STATUS
+               sll     k0, 3           /* extract cu0 bit */
+               bltz    k0, 9f
+
                ori     $28, sp, _THREAD_MASK
                xori    $28, _THREAD_MASK
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
                .set    mips64
                pref    0, 0($28)       /* Prefetch the current pointer */
 #endif
+9:
                .set    pop
                .endm
 
index 154e203..ec053ce 100644 (file)
@@ -101,6 +101,7 @@ void output_thread_info_defines(void)
        OFFSET(TI_REGS, thread_info, regs);
        DEFINE(_THREAD_SIZE, THREAD_SIZE);
        DEFINE(_THREAD_MASK, THREAD_MASK);
+       DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE);
        BLANK();
 }
 
index baa7b6f..619e30e 100644 (file)
@@ -188,9 +188,44 @@ NESTED(handle_int, PT_SIZE, sp)
 
        LONG_L  s0, TI_REGS($28)
        LONG_S  sp, TI_REGS($28)
-       PTR_LA  ra, ret_from_irq
-       PTR_LA  v0, plat_irq_dispatch
-       jr      v0
+
+       /*
+        * SAVE_ALL ensures we are using a valid kernel stack for the thread.
+        * Check if we are already using the IRQ stack.
+        */
+       move    s1, sp # Preserve the sp
+
+       /* Get IRQ stack for this CPU */
+       ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+       lui     k1, %hi(irq_stack)
+#else
+       lui     k1, %highest(irq_stack)
+       daddiu  k1, %higher(irq_stack)
+       dsll    k1, 16
+       daddiu  k1, %hi(irq_stack)
+       dsll    k1, 16
+#endif
+       LONG_SRL        k0, SMP_CPUID_PTRSHIFT
+       LONG_ADDU       k1, k0
+       LONG_L  t0, %lo(irq_stack)(k1)
+
+       # Check if already on IRQ stack
+       PTR_LI  t1, ~(_THREAD_SIZE-1)
+       and     t1, t1, sp
+       beq     t0, t1, 2f
+
+       /* Switch to IRQ stack */
+       li      t1, _IRQ_STACK_SIZE
+       PTR_ADD sp, t0, t1
+
+2:
+       jal     plat_irq_dispatch
+
+       /* Restore sp */
+       move    sp, s1
+
+       j       ret_from_irq
 #ifdef CONFIG_CPU_MICROMIPS
        nop
 #endif
@@ -263,8 +298,44 @@ NESTED(except_vec_vi_handler, 0, sp)
 
        LONG_L  s0, TI_REGS($28)
        LONG_S  sp, TI_REGS($28)
-       PTR_LA  ra, ret_from_irq
-       jr      v0
+
+       /*
+        * SAVE_ALL ensures we are using a valid kernel stack for the thread.
+        * Check if we are already using the IRQ stack.
+        */
+       move    s1, sp # Preserve the sp
+
+       /* Get IRQ stack for this CPU */
+       ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+       lui     k1, %hi(irq_stack)
+#else
+       lui     k1, %highest(irq_stack)
+       daddiu  k1, %higher(irq_stack)
+       dsll    k1, 16
+       daddiu  k1, %hi(irq_stack)
+       dsll    k1, 16
+#endif
+       LONG_SRL        k0, SMP_CPUID_PTRSHIFT
+       LONG_ADDU       k1, k0
+       LONG_L  t0, %lo(irq_stack)(k1)
+
+       # Check if already on IRQ stack
+       PTR_LI  t1, ~(_THREAD_SIZE-1)
+       and     t1, t1, sp
+       beq     t0, t1, 2f
+
+       /* Switch to IRQ stack */
+       li      t1, _IRQ_STACK_SIZE
+       PTR_ADD sp, t0, t1
+
+2:
+       jalr    v0
+
+       /* Restore sp */
+       move    sp, s1
+
+       j       ret_from_irq
        END(except_vec_vi_handler)
 
 /*
index 8eb5af8..dc1180a 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
 
+void *irq_stack[NR_CPUS];
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -55,6 +57,15 @@ void __init init_IRQ(void)
                irq_set_noprobe(i);
 
        arch_init_irq();
+
+       for_each_possible_cpu(i) {
+               int irq_pages = IRQ_STACK_SIZE / PAGE_SIZE;
+               void *s = (void *)__get_free_pages(GFP_KERNEL, irq_pages);
+
+               irq_stack[i] = s;
+               pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i,
+                       irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE);
+       }
 }
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
index fc537d1..8c26eca 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/cpu.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
+#include <asm/irq.h>
 #include <asm/msa.h>
 #include <asm/pgtable.h>
 #include <asm/mipsregs.h>
@@ -552,7 +553,19 @@ EXPORT_SYMBOL(unwind_stack_by_address);
 unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
                           unsigned long pc, unsigned long *ra)
 {
-       unsigned long stack_page = (unsigned long)task_stack_page(task);
+       unsigned long stack_page = 0;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               if (on_irq_stack(cpu, *sp)) {
+                       stack_page = (unsigned long)irq_stack[cpu];
+                       break;
+               }
+       }
+
+       if (!stack_page)
+               stack_page = (unsigned long)task_stack_page(task);
+
        return unwind_stack_by_address(stack_page, sp, pc, ra);
 }
 #endif
index 3e390a4..daf580c 100644 (file)
@@ -467,7 +467,7 @@ void __init ltq_soc_init(void)
 
                if (!np_xbar)
                        panic("Failed to load xbar nodes from devicetree");
-               if (of_address_to_resource(np_pmu, 0, &res_xbar))
+               if (of_address_to_resource(np_xbar, 0, &res_xbar))
                        panic("Failed to get xbar resources");
                if (request_mem_region(res_xbar.start, resource_size(&res_xbar),
                        res_xbar.name) < 0)
index 29f73e0..63b7d6f 100644 (file)
@@ -757,7 +757,8 @@ static void build_huge_update_entries(u32 **p, unsigned int pte,
 static void build_huge_handler_tail(u32 **p, struct uasm_reloc **r,
                                    struct uasm_label **l,
                                    unsigned int pte,
-                                   unsigned int ptr)
+                                   unsigned int ptr,
+                                   unsigned int flush)
 {
 #ifdef CONFIG_SMP
        UASM_i_SC(p, pte, 0, ptr);
@@ -766,6 +767,22 @@ static void build_huge_handler_tail(u32 **p, struct uasm_reloc **r,
 #else
        UASM_i_SW(p, pte, 0, ptr);
 #endif
+       if (cpu_has_ftlb && flush) {
+               BUG_ON(!cpu_has_tlbinv);
+
+               UASM_i_MFC0(p, ptr, C0_ENTRYHI);
+               uasm_i_ori(p, ptr, ptr, MIPS_ENTRYHI_EHINV);
+               UASM_i_MTC0(p, ptr, C0_ENTRYHI);
+               build_tlb_write_entry(p, l, r, tlb_indexed);
+
+               uasm_i_xori(p, ptr, ptr, MIPS_ENTRYHI_EHINV);
+               UASM_i_MTC0(p, ptr, C0_ENTRYHI);
+               build_huge_update_entries(p, pte, ptr);
+               build_huge_tlb_write_entry(p, l, r, pte, tlb_random, 0);
+
+               return;
+       }
+
        build_huge_update_entries(p, pte, ptr);
        build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0);
 }
@@ -2082,7 +2099,7 @@ static void build_r4000_tlb_load_handler(void)
                uasm_l_tlbl_goaround2(&l, p);
        }
        uasm_i_ori(&p, wr.r1, wr.r1, (_PAGE_ACCESSED | _PAGE_VALID));
-       build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
+       build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2, 1);
 #endif
 
        uasm_l_nopage_tlbl(&l, p);
@@ -2137,7 +2154,7 @@ static void build_r4000_tlb_store_handler(void)
        build_tlb_probe_entry(&p);
        uasm_i_ori(&p, wr.r1, wr.r1,
                   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-       build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
+       build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2, 1);
 #endif
 
        uasm_l_nopage_tlbs(&l, p);
@@ -2193,7 +2210,7 @@ static void build_r4000_tlb_modify_handler(void)
        build_tlb_probe_entry(&p);
        uasm_i_ori(&p, wr.r1, wr.r1,
                   _PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
-       build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2);
+       build_huge_handler_tail(&p, &r, &l, wr.r1, wr.r2, 0);
 #endif
 
        uasm_l_nopage_tlbm(&l, p);
index f42834c..3c57509 100644 (file)
@@ -36,7 +36,7 @@ static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) };
 static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
 static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
 static struct rt2880_pmx_func lna_a_func[] = { FUNC("lna a", 0, 32, 3) };
-static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna a", 0, 35, 3) };
+static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna g", 0, 35, 3) };
 static struct rt2880_pmx_func pci_func[] = {
        FUNC("pci-dev", 0, 40, 32),
        FUNC("pci-host2", 1, 40, 32),
@@ -44,7 +44,7 @@ static struct rt2880_pmx_func pci_func[] = {
        FUNC("pci-fnc", 3, 40, 32)
 };
 static struct rt2880_pmx_func ge1_func[] = { FUNC("ge1", 0, 72, 12) };
-static struct rt2880_pmx_func ge2_func[] = { FUNC("ge1", 0, 84, 12) };
+static struct rt2880_pmx_func ge2_func[] = { FUNC("ge2", 0, 84, 12) };
 
 static struct rt2880_pmx_group rt3883_pinmux_data[] = {
        GRP("i2c", i2c_func, 1, RT3883_GPIO_MODE_I2C),
index 718dd19..de73beb 100644 (file)
@@ -48,6 +48,13 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
        return alloc_bootmem_align(size, align);
 }
 
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
+                                            bool nomap)
+{
+       reserve_bootmem(base, size, BOOTMEM_DEFAULT);
+       return 0;
+}
+
 void __init early_init_devtree(void *params)
 {
        __be32 *dtb = (u32 *)__dtb_start;
index a4ff86d..6c4e351 100644 (file)
@@ -195,6 +195,9 @@ void __init setup_arch(char **cmdline_p)
        }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
+       early_init_fdt_reserve_self();
+       early_init_fdt_scan_reserved_mem();
+
        unflatten_and_copy_device_tree();
 
        setup_cpuinfo();
index 86150fb..91e5c17 100644 (file)
@@ -808,14 +808,25 @@ int fix_alignment(struct pt_regs *regs)
        nb = aligninfo[instr].len;
        flags = aligninfo[instr].flags;
 
-       /* ldbrx/stdbrx overlap lfs/stfs in the DSISR unfortunately */
-       if (IS_XFORM(instruction) && ((instruction >> 1) & 0x3ff) == 532) {
-               nb = 8;
-               flags = LD+SW;
-       } else if (IS_XFORM(instruction) &&
-                  ((instruction >> 1) & 0x3ff) == 660) {
-               nb = 8;
-               flags = ST+SW;
+       /*
+        * Handle some cases which give overlaps in the DSISR values.
+        */
+       if (IS_XFORM(instruction)) {
+               switch (get_xop(instruction)) {
+               case 532:       /* ldbrx */
+                       nb = 8;
+                       flags = LD+SW;
+                       break;
+               case 660:       /* stdbrx */
+                       nb = 8;
+                       flags = ST+SW;
+                       break;
+               case 20:        /* lwarx */
+               case 84:        /* ldarx */
+               case 116:       /* lharx */
+               case 276:       /* lqarx */
+                       return 0;       /* not emulated ever */
+               }
        }
 
        /* Byteswap little endian loads and stores */
index edba294..f6fd033 100644 (file)
@@ -716,7 +716,7 @@ resume_kernel:
 
        addi    r8,r1,INT_FRAME_SIZE    /* Get the kprobed function entry */
 
-       lwz     r3,GPR1(r1)
+       l     r3,GPR1(r1)
        subi    r3,r3,INT_FRAME_SIZE    /* dst: Allocate a trampoline exception frame */
        mr      r4,r1                   /* src:  current exception frame */
        mr      r1,r3                   /* Reroute the trampoline frame to r1 */
@@ -730,8 +730,8 @@ resume_kernel:
        addi    r6,r6,8
        bdnz    2b
 
-       /* Do real store operation to complete stwu */
-       lwz     r5,GPR1(r1)
+       /* Do real store operation to complete stdu */
+       l     r5,GPR1(r1)
        std     r8,0(r5)
 
        /* Clear _TIF_EMULATE_STACK_STORE flag */
index 5c03a6a..a208232 100644 (file)
@@ -220,6 +220,15 @@ static void cpu_ready_for_interrupts(void)
                unsigned long lpcr = mfspr(SPRN_LPCR);
                mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
        }
+
+       /*
+        * Fixup HFSCR:TM based on CPU features. The bit is set by our
+        * early asm init because at that point we haven't updated our
+        * CPU features from firmware and device-tree. Here we have,
+        * so let's do it.
+        */
+       if (cpu_has_feature(CPU_FTR_HVMODE) && !cpu_has_feature(CPU_FTR_TM_COMP))
+               mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM);
 }
 
 /*
index c8822af..19d9b2d 100644 (file)
@@ -645,6 +645,10 @@ static void native_flush_hash_range(unsigned long number, int local)
        unsigned long psize = batch->psize;
        int ssize = batch->ssize;
        int i;
+       unsigned int use_local;
+
+       use_local = local && mmu_has_feature(MMU_FTR_TLBIEL) &&
+               mmu_psize_defs[psize].tlbiel && !cxl_ctx_in_use();
 
        local_irq_save(flags);
 
@@ -671,8 +675,7 @@ static void native_flush_hash_range(unsigned long number, int local)
                } pte_iterate_hashed_end();
        }
 
-       if (mmu_has_feature(MMU_FTR_TLBIEL) &&
-           mmu_psize_defs[psize].tlbiel && local) {
+       if (use_local) {
                asm volatile("ptesync":::"memory");
                for (i = 0; i < number; i++) {
                        vpn = batch->vpn[i];
index 4da604e..ca15613 100644 (file)
@@ -141,31 +141,34 @@ static void check_ipl_parmblock(void *start, unsigned long size)
 
 unsigned long decompress_kernel(void)
 {
-       unsigned long output_addr;
-       unsigned char *output;
+       void *output, *kernel_end;
 
-       output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL;
-       check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start);
-       memset(&_bss, 0, &_ebss - &_bss);
-       free_mem_ptr = (unsigned long)&_end;
-       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-       output = (unsigned char *) output_addr;
+       output = (void *) ALIGN((unsigned long) &_end + HEAP_SIZE, PAGE_SIZE);
+       kernel_end = output + SZ__bss_start;
+       check_ipl_parmblock((void *) 0, (unsigned long) kernel_end);
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /*
         * Move the initrd right behind the end of the decompressed
-        * kernel image.
+        * kernel image. This also prevents initrd corruption caused by
+        * bss clearing since kernel_end will always be located behind the
+        * current bss section..
         */
-       if (INITRD_START && INITRD_SIZE &&
-           INITRD_START < (unsigned long) output + SZ__bss_start) {
-               check_ipl_parmblock(output + SZ__bss_start,
-                                   INITRD_START + INITRD_SIZE);
-               memmove(output + SZ__bss_start,
-                       (void *) INITRD_START, INITRD_SIZE);
-               INITRD_START = (unsigned long) output + SZ__bss_start;
+       if (INITRD_START && INITRD_SIZE && kernel_end > (void *) INITRD_START) {
+               check_ipl_parmblock(kernel_end, INITRD_SIZE);
+               memmove(kernel_end, (void *) INITRD_START, INITRD_SIZE);
+               INITRD_START = (unsigned long) kernel_end;
        }
 #endif
 
+       /*
+        * Clear bss section. free_mem_ptr and free_mem_end_ptr need to be
+        * initialized afterwards since they reside in bss.
+        */
+       memset(&_bss, 0, &_ebss - &_bss);
+       free_mem_ptr = (unsigned long) &_end;
+       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
        puts("Uncompressing Linux... ");
        __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
        puts("Ok, booting the kernel.\n");
index 024f85f..e2c0e4e 100644 (file)
@@ -829,6 +829,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 {
        pgste_t pgste;
 
+       if (pte_present(entry))
+               pte_val(entry) &= ~_PAGE_UNUSED;
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
                pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
index 5c7381c..c8d837f 100644 (file)
@@ -150,7 +150,7 @@ unsigned long __must_check __copy_to_user(void __user *to, const void *from,
                "       jg      2b\n"                           \
                ".popsection\n"                                 \
                EX_TABLE(0b,3b) EX_TABLE(1b,3b)                 \
-               : "=d" (__rc), "=Q" (*(to))                     \
+               : "=d" (__rc), "+Q" (*(to))                     \
                : "d" (size), "Q" (*(from)),                    \
                  "d" (__reg0), "K" (-EFAULT)                   \
                : "cc");                                        \
index 08a317a..a7508d7 100644 (file)
@@ -31,8 +31,10 @@ static int __init vdso32_setup(char *s)
 {
        vdso32_enabled = simple_strtoul(s, NULL, 0);
 
-       if (vdso32_enabled > 1)
+       if (vdso32_enabled > 1) {
                pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
+               vdso32_enabled = 0;
+       }
 
        return 1;
 }
@@ -63,13 +65,18 @@ subsys_initcall(sysenter_setup);
 /* Register vsyscall32 into the ABI table */
 #include <linux/sysctl.h>
 
+static const int zero;
+static const int one = 1;
+
 static struct ctl_table abi_table2[] = {
        {
                .procname       = "vsyscall32",
                .data           = &vdso32_enabled,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (int *)&zero,
+               .extra2         = (int *)&one,
        },
        {}
 };
index 1514753..d262f98 100644 (file)
@@ -278,7 +278,7 @@ struct task_struct;
 
 #define        ARCH_DLINFO_IA32                                                \
 do {                                                                   \
-       if (vdso32_enabled) {                                           \
+       if (VDSO_CURRENT_BASE) {                                        \
                NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY);                    \
                NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE);        \
        }                                                               \
index d8ce3ec..bd8ce6b 100644 (file)
@@ -72,8 +72,8 @@ static inline void arch_wmb_pmem(void)
  * @size:      number of bytes to write back
  *
  * Write back a cache range using the CLWB (cache line write back)
- * instruction.  This function requires explicit ordering with an
- * arch_wmb_pmem() call.  This API is internal to the x86 PMEM implementation.
+ * instruction. Note that @size is internally rounded up to be cache
+ * line size aligned.
  */
 static inline void __arch_wb_cache_pmem(void *vaddr, size_t size)
 {
@@ -87,15 +87,6 @@ static inline void __arch_wb_cache_pmem(void *vaddr, size_t size)
                clwb(p);
 }
 
-/*
- * copy_from_iter_nocache() on x86 only uses non-temporal stores for iovec
- * iterators, so for other types (bvec & kvec) we must do a cache write-back.
- */
-static inline bool __iter_needs_pmem_wb(struct iov_iter *i)
-{
-       return iter_is_iovec(i) == false;
-}
-
 /**
  * arch_copy_from_iter_pmem - copy data from an iterator to PMEM
  * @addr:      PMEM destination address
@@ -114,8 +105,36 @@ static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
        /* TODO: skip the write-back by always using non-temporal stores */
        len = copy_from_iter_nocache(vaddr, bytes, i);
 
-       if (__iter_needs_pmem_wb(i))
-               __arch_wb_cache_pmem(vaddr, bytes);
+       /*
+        * In the iovec case on x86_64 copy_from_iter_nocache() uses
+        * non-temporal stores for the bulk of the transfer, but we need
+        * to manually flush if the transfer is unaligned. A cached
+        * memory copy is used when destination or size is not naturally
+        * aligned. That is:
+        *   - Require 8-byte alignment when size is 8 bytes or larger.
+        *   - Require 4-byte alignment when size is 4 bytes.
+        *
+        * In the non-iovec case the entire destination needs to be
+        * flushed.
+        */
+       if (iter_is_iovec(i)) {
+               unsigned long flushed, dest = (unsigned long) addr;
+
+               if (bytes < 8) {
+                       if (!IS_ALIGNED(dest, 4) || (bytes != 4))
+                               __arch_wb_cache_pmem(addr, 1);
+               } else {
+                       if (!IS_ALIGNED(dest, 8)) {
+                               dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
+                               __arch_wb_cache_pmem(addr, 1);
+                       }
+
+                       flushed = dest - (unsigned long) addr;
+                       if (bytes > flushed && !IS_ALIGNED(bytes - flushed, 8))
+                               __arch_wb_cache_pmem(addr + bytes - 1, 1);
+               }
+       } else
+               __arch_wb_cache_pmem(addr, bytes);
 
        return len;
 }
index e99b150..62aca44 100644 (file)
@@ -53,7 +53,7 @@ static const char * const th_names[] = {
        "load_store",
        "insn_fetch",
        "combined_unit",
-       "",
+       "decode_unit",
        "northbridge",
        "execution_unit",
 };
index 659f01e..8900400 100644 (file)
@@ -410,6 +410,9 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
                cpuc->lbr_entries[i].to         = msr_lastbranch.to;
                cpuc->lbr_entries[i].mispred    = 0;
                cpuc->lbr_entries[i].predicted  = 0;
+               cpuc->lbr_entries[i].in_tx      = 0;
+               cpuc->lbr_entries[i].abort      = 0;
+               cpuc->lbr_entries[i].cycles     = 0;
                cpuc->lbr_entries[i].reserved   = 0;
        }
        cpuc->lbr_stack.nr = i;
index 3a7ae80..0a472e9 100644 (file)
@@ -6678,14 +6678,20 @@ static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason,
                }
 
                page = nested_get_page(vcpu, vmptr);
-               if (page == NULL ||
-                   *(u32 *)kmap(page) != VMCS12_REVISION) {
+               if (page == NULL) {
                        nested_vmx_failInvalid(vcpu);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+               if (*(u32 *)kmap(page) != VMCS12_REVISION) {
                        kunmap(page);
+                       nested_release_page_clean(page);
+                       nested_vmx_failInvalid(vcpu);
                        skip_emulated_instruction(vcpu);
                        return 1;
                }
                kunmap(page);
+               nested_release_page_clean(page);
                vmx->nested.vmxon_ptr = vmptr;
                break;
        case EXIT_REASON_VMCLEAR:
index 493f541..3aebbd6 100644 (file)
@@ -628,21 +628,40 @@ void __init init_mem_mapping(void)
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address
  * is valid. The argument is a physical page number.
  *
- *
- * On x86, access has to be given to the first megabyte of ram because that area
- * contains BIOS code and data regions used by X and dosemu and similar apps.
- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
- * mmio resources as well as potential bios/acpi data regions.
+ * On x86, access has to be given to the first megabyte of RAM because that
+ * area traditionally contains BIOS code and data regions used by X, dosemu,
+ * and similar apps. Since they map the entire memory range, the whole range
+ * must be allowed (for mapping), but any areas that would otherwise be
+ * disallowed are flagged as being "zero filled" instead of rejected.
+ * Access has to be given to non-kernel-ram areas as well, these contain the
+ * PCI mmio resources as well as potential bios/acpi data regions.
  */
 int devmem_is_allowed(unsigned long pagenr)
 {
-       if (pagenr < 256)
-               return 1;
-       if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
+       if (page_is_ram(pagenr)) {
+               /*
+                * For disallowed memory regions in the low 1MB range,
+                * request that the page be shown as all zeros.
+                */
+               if (pagenr < 256)
+                       return 2;
+
+               return 0;
+       }
+
+       /*
+        * This must follow RAM test, since System RAM is considered a
+        * restricted resource under CONFIG_STRICT_IOMEM.
+        */
+       if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
+               /* Low 1MB bypasses iomem restrictions. */
+               if (pagenr < 256)
+                       return 1;
+
                return 0;
-       if (!page_is_ram(pagenr))
-               return 1;
-       return 0;
+       }
+
+       return 1;
 }
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
index e345891..df8844a 100644 (file)
@@ -713,10 +713,9 @@ static void __init xen_reserve_xen_mfnlist(void)
                size = PFN_PHYS(xen_start_info->nr_p2m_frames);
        }
 
-       if (!xen_is_e820_reserved(start, size)) {
-               memblock_reserve(start, size);
+       memblock_reserve(start, size);
+       if (!xen_is_e820_reserved(start, size))
                return;
-       }
 
 #ifdef CONFIG_X86_32
        /*
@@ -727,6 +726,7 @@ static void __init xen_reserve_xen_mfnlist(void)
        BUG();
 #else
        xen_relocate_p2m();
+       memblock_free(start, size);
 #endif
 }
 
index 02c4d9b..8978272 100644 (file)
@@ -375,10 +375,14 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
        bio_list_init(&punt);
        bio_list_init(&nopunt);
 
-       while ((bio = bio_list_pop(current->bio_list)))
+       while ((bio = bio_list_pop(&current->bio_list[0])))
                bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
+       current->bio_list[0] = nopunt;
 
-       *current->bio_list = nopunt;
+       bio_list_init(&nopunt);
+       while ((bio = bio_list_pop(&current->bio_list[1])))
+               bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
+       current->bio_list[1] = nopunt;
 
        spin_lock(&bs->rescue_lock);
        bio_list_merge(&bs->rescue_list, &punt);
@@ -466,7 +470,9 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
                 * we retry with the original gfp_flags.
                 */
 
-               if (current->bio_list && !bio_list_empty(current->bio_list))
+               if (current->bio_list &&
+                   (!bio_list_empty(&current->bio_list[0]) ||
+                    !bio_list_empty(&current->bio_list[1])))
                        gfp_mask &= ~__GFP_DIRECT_RECLAIM;
 
                p = mempool_alloc(bs->bio_pool, gfp_mask);
index 500447b..3115494 100644 (file)
@@ -2038,7 +2038,14 @@ end_io:
  */
 blk_qc_t generic_make_request(struct bio *bio)
 {
-       struct bio_list bio_list_on_stack;
+       /*
+        * bio_list_on_stack[0] contains bios submitted by the current
+        * make_request_fn.
+        * bio_list_on_stack[1] contains bios that were submitted before
+        * the current make_request_fn, but that haven't been processed
+        * yet.
+        */
+       struct bio_list bio_list_on_stack[2];
        blk_qc_t ret = BLK_QC_T_NONE;
 
        if (!generic_make_request_checks(bio))
@@ -2055,7 +2062,7 @@ blk_qc_t generic_make_request(struct bio *bio)
         * should be added at the tail
         */
        if (current->bio_list) {
-               bio_list_add(current->bio_list, bio);
+               bio_list_add(&current->bio_list[0], bio);
                goto out;
        }
 
@@ -2074,24 +2081,39 @@ blk_qc_t generic_make_request(struct bio *bio)
         * bio_list, and call into ->make_request() again.
         */
        BUG_ON(bio->bi_next);
-       bio_list_init(&bio_list_on_stack);
-       current->bio_list = &bio_list_on_stack;
+       bio_list_init(&bio_list_on_stack[0]);
+       current->bio_list = bio_list_on_stack;
        do {
                struct request_queue *q = bdev_get_queue(bio->bi_bdev);
 
                if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) {
+                       struct bio_list lower, same;
+
+                       /* Create a fresh bio_list for all subordinate requests */
+                       bio_list_on_stack[1] = bio_list_on_stack[0];
+                       bio_list_init(&bio_list_on_stack[0]);
 
                        ret = q->make_request_fn(q, bio);
 
                        blk_queue_exit(q);
-
-                       bio = bio_list_pop(current->bio_list);
+                       /* sort new bios into those for a lower level
+                        * and those for the same level
+                        */
+                       bio_list_init(&lower);
+                       bio_list_init(&same);
+                       while ((bio = bio_list_pop(&bio_list_on_stack[0])) != NULL)
+                               if (q == bdev_get_queue(bio->bi_bdev))
+                                       bio_list_add(&same, bio);
+                               else
+                                       bio_list_add(&lower, bio);
+                       /* now assemble so we handle the lowest level first */
+                       bio_list_merge(&bio_list_on_stack[0], &lower);
+                       bio_list_merge(&bio_list_on_stack[0], &same);
+                       bio_list_merge(&bio_list_on_stack[0], &bio_list_on_stack[1]);
                } else {
-                       struct bio *bio_next = bio_list_pop(current->bio_list);
-
                        bio_io_error(bio);
-                       bio = bio_next;
                }
+               bio = bio_list_pop(&bio_list_on_stack[0]);
        } while (bio);
        current->bio_list = NULL; /* deactivate */
 
index 8bd5483..1452db0 100644 (file)
@@ -1470,7 +1470,7 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
        INIT_LIST_HEAD(&tags->page_list);
 
        tags->rqs = kzalloc_node(set->queue_depth * sizeof(struct request *),
-                                GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY,
+                                GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
                                 set->numa_node);
        if (!tags->rqs) {
                blk_mq_free_tags(tags);
@@ -1496,7 +1496,7 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
 
                do {
                        page = alloc_pages_node(set->numa_node,
-                               GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO,
+                               GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO,
                                this_order);
                        if (page)
                                break;
@@ -1517,7 +1517,7 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
                 * Allow kmemleak to scan these pages as they contain pointers
                 * to additional allocations like via ops->init_request().
                 */
-               kmemleak_alloc(p, order_to_size(this_order), 1, GFP_KERNEL);
+               kmemleak_alloc(p, order_to_size(this_order), 1, GFP_NOIO);
                entries_per_page = order_to_size(this_order) / rq_size;
                to_do = min(entries_per_page, set->queue_depth - i);
                left -= to_do * rq_size;
index 7f1e8f8..de2a616 100644 (file)
@@ -673,7 +673,6 @@ void del_gendisk(struct gendisk *disk)
 
        kobject_put(disk->part0.holder_dir);
        kobject_put(disk->slave_dir);
-       disk->driverfs_dev = NULL;
        if (!sysfs_deprecated)
                sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
        pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
index dac1c24..f9caf0f 100644 (file)
@@ -31,6 +31,7 @@ struct ahash_request_priv {
        crypto_completion_t complete;
        void *data;
        u8 *result;
+       u32 flags;
        void *ubuf[] CRYPTO_MINALIGN_ATTR;
 };
 
@@ -270,6 +271,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
        priv->result = req->result;
        priv->complete = req->base.complete;
        priv->data = req->base.data;
+       priv->flags = req->base.flags;
+
        /*
         * WARNING: We do not backup req->priv here! The req->priv
         *          is for internal use of the Crypto API and the
@@ -284,38 +287,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
        return 0;
 }
 
-static void ahash_restore_req(struct ahash_request *req)
+static void ahash_restore_req(struct ahash_request *req, int err)
 {
        struct ahash_request_priv *priv = req->priv;
 
+       if (!err)
+               memcpy(priv->result, req->result,
+                      crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+
        /* Restore the original crypto request. */
        req->result = priv->result;
-       req->base.complete = priv->complete;
-       req->base.data = priv->data;
+
+       ahash_request_set_callback(req, priv->flags,
+                                  priv->complete, priv->data);
        req->priv = NULL;
 
        /* Free the req->priv.priv from the ADJUSTED request. */
        kzfree(priv);
 }
 
-static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
+static void ahash_notify_einprogress(struct ahash_request *req)
 {
        struct ahash_request_priv *priv = req->priv;
+       struct crypto_async_request oreq;
 
-       if (err == -EINPROGRESS)
-               return;
-
-       if (!err)
-               memcpy(priv->result, req->result,
-                      crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+       oreq.data = priv->data;
 
-       ahash_restore_req(req);
+       priv->complete(&oreq, -EINPROGRESS);
 }
 
 static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
 {
        struct ahash_request *areq = req->data;
 
+       if (err == -EINPROGRESS) {
+               ahash_notify_einprogress(areq);
+               return;
+       }
+
        /*
         * Restore the original request, see ahash_op_unaligned() for what
         * goes where.
@@ -326,7 +335,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
         */
 
        /* First copy req->result into req->priv.result */
-       ahash_op_unaligned_finish(areq, err);
+       ahash_restore_req(areq, err);
 
        /* Complete the ORIGINAL request. */
        areq->base.complete(&areq->base, err);
@@ -342,7 +351,12 @@ static int ahash_op_unaligned(struct ahash_request *req,
                return err;
 
        err = op(req);
-       ahash_op_unaligned_finish(req, err);
+       if (err == -EINPROGRESS ||
+           (err == -EBUSY && (ahash_request_flags(req) &
+                              CRYPTO_TFM_REQ_MAY_BACKLOG)))
+               return err;
+
+       ahash_restore_req(req, err);
 
        return err;
 }
@@ -377,25 +391,14 @@ int crypto_ahash_digest(struct ahash_request *req)
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_digest);
 
-static void ahash_def_finup_finish2(struct ahash_request *req, int err)
+static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
 {
-       struct ahash_request_priv *priv = req->priv;
+       struct ahash_request *areq = req->data;
 
        if (err == -EINPROGRESS)
                return;
 
-       if (!err)
-               memcpy(priv->result, req->result,
-                      crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
-
-       ahash_restore_req(req);
-}
-
-static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
-{
-       struct ahash_request *areq = req->data;
-
-       ahash_def_finup_finish2(areq, err);
+       ahash_restore_req(areq, err);
 
        areq->base.complete(&areq->base, err);
 }
@@ -406,11 +409,15 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err)
                goto out;
 
        req->base.complete = ahash_def_finup_done2;
-       req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
        err = crypto_ahash_reqtfm(req)->final(req);
+       if (err == -EINPROGRESS ||
+           (err == -EBUSY && (ahash_request_flags(req) &
+                              CRYPTO_TFM_REQ_MAY_BACKLOG)))
+               return err;
 
 out:
-       ahash_def_finup_finish2(req, err);
+       ahash_restore_req(req, err);
        return err;
 }
 
@@ -418,7 +425,16 @@ static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
 {
        struct ahash_request *areq = req->data;
 
+       if (err == -EINPROGRESS) {
+               ahash_notify_einprogress(areq);
+               return;
+       }
+
+       areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
        err = ahash_def_finup_finish1(areq, err);
+       if (areq->priv)
+               return;
 
        areq->base.complete(&areq->base, err);
 }
@@ -433,6 +449,11 @@ static int ahash_def_finup(struct ahash_request *req)
                return err;
 
        err = tfm->update(req);
+       if (err == -EINPROGRESS ||
+           (err == -EBUSY && (ahash_request_flags(req) &
+                              CRYPTO_TFM_REQ_MAY_BACKLOG)))
+               return err;
+
        return ahash_def_finup_finish1(req, err);
 }
 
index 675eaf3..b9cebca 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for the Linux ACPI interpreter
 #
 
-ccflags-y                      := -Os
 ccflags-$(CONFIG_ACPI_DEBUG)   += -DACPI_DEBUG_OUTPUT
 
 #
index 296b7a1..5365ff6 100644 (file)
 ACPI_MODULE_NAME("platform");
 
 static const struct acpi_device_id forbidden_id_list[] = {
-       {"PNP0000", 0}, /* PIC */
-       {"PNP0100", 0}, /* Timer */
-       {"PNP0200", 0}, /* AT DMA Controller */
+       {"PNP0000",  0},        /* PIC */
+       {"PNP0100",  0},        /* Timer */
+       {"PNP0200",  0},        /* AT DMA Controller */
+       {"ACPI0009", 0},        /* IOxAPIC */
+       {"ACPI000A", 0},        /* IOAPIC */
        {"", 0},
 };
 
index 14c2a07..67d7489 100644 (file)
@@ -979,7 +979,11 @@ static int cmp_map(const void *m0, const void *m1)
        const struct nfit_set_info_map *map0 = m0;
        const struct nfit_set_info_map *map1 = m1;
 
-       return map0->region_offset - map1->region_offset;
+       if (map0->region_offset < map1->region_offset)
+               return -1;
+       else if (map0->region_offset > map1->region_offset)
+               return 1;
+       return 0;
 }
 
 /* Retrieve the nth entry referencing this spa */
index fcd4ce6..1c2b846 100644 (file)
@@ -200,6 +200,7 @@ static int acpi_power_get_list_state(struct list_head *list, int *state)
                return -EINVAL;
 
        /* The state of the list is 'on' IFF all resources are 'on'. */
+       cur_state = 0;
        list_for_each_entry(entry, list, node) {
                struct acpi_power_resource *resource = entry->resource;
                acpi_handle handle = resource->device.handle;
index 76ac317..c5a2057 100644 (file)
@@ -581,13 +581,13 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
 
        if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
                bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
-               clear_page(mem);
+               memset(mem, 0, PAGE_SIZE);
                return 0;
        }
 
        cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
        if (size == PAGE_SIZE)
-               copy_page(mem, cmem);
+               memcpy(mem, cmem, PAGE_SIZE);
        else
                ret = zcomp_decompress(zram->comp, cmem, size, mem);
        zs_unmap_object(meta->mem_pool, handle);
@@ -750,7 +750,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 
        if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
                src = kmap_atomic(page);
-               copy_page(cmem, src);
+               memcpy(cmem, src, PAGE_SIZE);
                kunmap_atomic(src);
        } else {
                memcpy(cmem, src, clen);
index 5d105fb..e67c696 100644 (file)
@@ -13,7 +13,7 @@
 #define BTFM_SLIM_H
 #include <linux/slimbus/slimbus.h>
 
-#define BTFMSLIM_DBG(fmt, arg...)  pr_debug(fmt "\n", ## arg)
+#define BTFMSLIM_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n", __func__, ## arg)
 #define BTFMSLIM_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg)
 #define BTFMSLIM_ERR(fmt, arg...)  pr_err("%s: " fmt "\n", __func__, ## arg)
 
index c93b292..a451ff3 100644 (file)
@@ -83,19 +83,34 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
 {
        int ret = 0;
        uint8_t reg_val = 0;
+       uint8_t port_bit = 0;
        uint16_t reg;
 
        BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
        if (rxport) {
+               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)",
+                                       reg_val, reg);
+                       ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
+                       if (ret) {
+                               BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+                                               ret, reg);
+                               goto error;
+                       }
+               }
                /* Port enable */
                reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10);
                goto enable_disable_rxport;
        }
-       /* txport */
        if (!enable)
                goto enable_disable_txport;
 
-       /* Multiple Channel Setting - only for FM Tx */
+       /* txport */
+       /* Multiple Channel Setting */
        if (is_fm_port(port_num)) {
                reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) |
                                (0x1 << CHRK_SB_PGD_PORT_TX2_FM);
@@ -105,6 +120,18 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
                        BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
                        goto error;
                }
+       } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
+               /* SCO Tx */
+               reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
+               reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+               BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+                               reg_val, reg);
+               ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
+               if (ret) {
+                       BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+                                       ret, reg);
+                       goto error;
+               }
        }
 
        /* Enable Tx port hw auto recovery for underrun or overrun error */
index 4bbe4e5..db8eb7c 100644 (file)
@@ -585,10 +585,12 @@ config TELCLOCK
          controlling the behavior of this hardware.
 
 config DEVPORT
-       bool
-       depends on !M68K
+       bool "/dev/port character device"
        depends on ISA || PCI
        default y
+       help
+         Say Y here if you want to support the /dev/port device. The /dev/port
+         device is similar to /dev/mem, but for I/O ports.
 
 source "drivers/s390/char/Kconfig"
 
index 10c4d8c..7e44b38 100644 (file)
@@ -1465,6 +1465,7 @@ static void fastrpc_init(struct fastrpc_apps *me)
 {
        int i;
        INIT_HLIST_HEAD(&me->drivers);
+       INIT_HLIST_HEAD(&me->maps);
        spin_lock_init(&me->hlock);
        mutex_init(&me->smd_mutex);
        me->channel = &gcinfo[0];
@@ -2791,7 +2792,7 @@ static int fastrpc_cb_probe(struct device *dev)
                start = 0x60000000;
        VERIFY(err, !IS_ERR_OR_NULL(sess->smmu.mapping =
                                arm_iommu_create_mapping(&platform_bus_type,
-                                               start, 0x7fffffff)));
+                                               start, 0x70000000)));
        if (err)
                goto bail;
        iommu_set_fault_handler(sess->smmu.mapping->domain,
index 2784cf7..03d496c 100644 (file)
@@ -487,6 +487,18 @@ static void diag_glink_remote_disconnect_work_fn(struct work_struct *work)
        atomic_set(&glink_info->tx_intent_ready, 0);
 }
 
+static void diag_glink_late_init_work_fn(struct work_struct *work)
+{
+       struct diag_glink_info *glink_info = container_of(work,
+                                                       struct diag_glink_info,
+                                                       late_init_work);
+       if (!glink_info || !glink_info->hdl)
+               return;
+       DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d\n",
+                       glink_info->peripheral, glink_info->type);
+       diagfwd_channel_open(glink_info->fwd_ctxt);
+}
+
 static void diag_glink_transport_notify_state(void *handle, const void *priv,
                                          unsigned event)
 {
@@ -617,7 +629,7 @@ static void glink_late_init(struct diag_glink_info *glink_info)
        glink_info->inited = 1;
 
        if (atomic_read(&glink_info->opened))
-               diagfwd_channel_open(glink_info->fwd_ctxt);
+               queue_work(glink_info->wq, &(glink_info->late_init_work));
 
        DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
                 glink_info->name);
@@ -665,6 +677,7 @@ static void __diag_glink_init(struct diag_glink_info *glink_info)
        INIT_WORK(&(glink_info->connect_work), diag_glink_connect_work_fn);
        INIT_WORK(&(glink_info->remote_disconnect_work),
                diag_glink_remote_disconnect_work_fn);
+       INIT_WORK(&(glink_info->late_init_work), diag_glink_late_init_work_fn);
        link_info.glink_link_state_notif_cb = diag_glink_notify_cb;
        link_info.transport = NULL;
        link_info.edge = glink_info->edge;
index 5c1abef..a84fa4e 100644 (file)
@@ -37,6 +37,7 @@ struct diag_glink_info {
        struct work_struct read_work;
        struct work_struct connect_work;
        struct work_struct remote_disconnect_work;
+       struct work_struct late_init_work;
        struct diagfwd_info *fwd_ctxt;
 };
 
index 6b1721f..e901463 100644 (file)
@@ -59,6 +59,10 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
 #endif
 
 #ifdef CONFIG_STRICT_DEVMEM
+static inline int page_is_allowed(unsigned long pfn)
+{
+       return devmem_is_allowed(pfn);
+}
 static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 {
        u64 from = ((u64)pfn) << PAGE_SHIFT;
@@ -78,6 +82,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
        return 1;
 }
 #else
+static inline int page_is_allowed(unsigned long pfn)
+{
+       return 1;
+}
 static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 {
        return 1;
@@ -125,23 +133,31 @@ static ssize_t read_mem(struct file *file, char __user *buf,
 
        while (count > 0) {
                unsigned long remaining;
+               int allowed;
 
                sz = size_inside_page(p, count);
 
-               if (!range_is_allowed(p >> PAGE_SHIFT, count))
+               allowed = page_is_allowed(p >> PAGE_SHIFT);
+               if (!allowed)
                        return -EPERM;
+               if (allowed == 2) {
+                       /* Show zeros for restricted memory. */
+                       remaining = clear_user(buf, sz);
+               } else {
+                       /*
+                        * On ia64 if a page has been mapped somewhere as
+                        * uncached, then it must also be accessed uncached
+                        * by the kernel or data corruption may occur.
+                        */
+                       ptr = xlate_dev_mem_ptr(p);
+                       if (!ptr)
+                               return -EFAULT;
 
-               /*
-                * On ia64 if a page has been mapped somewhere as uncached, then
-                * it must also be accessed uncached by the kernel or data
-                * corruption may occur.
-                */
-               ptr = xlate_dev_mem_ptr(p);
-               if (!ptr)
-                       return -EFAULT;
+                       remaining = copy_to_user(buf, ptr, sz);
+
+                       unxlate_dev_mem_ptr(p, ptr);
+               }
 
-               remaining = copy_to_user(buf, ptr, sz);
-               unxlate_dev_mem_ptr(p, ptr);
                if (remaining)
                        return -EFAULT;
 
@@ -184,30 +200,36 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
 #endif
 
        while (count > 0) {
+               int allowed;
+
                sz = size_inside_page(p, count);
 
-               if (!range_is_allowed(p >> PAGE_SHIFT, sz))
+               allowed = page_is_allowed(p >> PAGE_SHIFT);
+               if (!allowed)
                        return -EPERM;
 
-               /*
-                * On ia64 if a page has been mapped somewhere as uncached, then
-                * it must also be accessed uncached by the kernel or data
-                * corruption may occur.
-                */
-               ptr = xlate_dev_mem_ptr(p);
-               if (!ptr) {
-                       if (written)
-                               break;
-                       return -EFAULT;
-               }
+               /* Skip actual writing when a page is marked as restricted. */
+               if (allowed == 1) {
+                       /*
+                        * On ia64 if a page has been mapped somewhere as
+                        * uncached, then it must also be accessed uncached
+                        * by the kernel or data corruption may occur.
+                        */
+                       ptr = xlate_dev_mem_ptr(p);
+                       if (!ptr) {
+                               if (written)
+                                       break;
+                               return -EFAULT;
+                       }
 
-               copied = copy_from_user(ptr, buf, sz);
-               unxlate_dev_mem_ptr(p, ptr);
-               if (copied) {
-                       written += sz - copied;
-                       if (written)
-                               break;
-                       return -EFAULT;
+                       copied = copy_from_user(ptr, buf, sz);
+                       unxlate_dev_mem_ptr(p, ptr);
+                       if (copied) {
+                               written += sz - copied;
+                               if (written)
+                                       break;
+                               return -EFAULT;
+                       }
                }
 
                buf += sz;
index 090183f..31e8ae9 100644 (file)
@@ -1130,6 +1130,8 @@ static int put_chars(u32 vtermno, const char *buf, int count)
 {
        struct port *port;
        struct scatterlist sg[1];
+       void *data;
+       int ret;
 
        if (unlikely(early_put_chars))
                return early_put_chars(vtermno, buf, count);
@@ -1138,8 +1140,14 @@ static int put_chars(u32 vtermno, const char *buf, int count)
        if (!port)
                return -EPIPE;
 
-       sg_init_one(sg, buf, count);
-       return __send_to_port(port, sg, 1, count, (void *)buf, false);
+       data = kmemdup(buf, count, GFP_ATOMIC);
+       if (!data)
+               return -ENOMEM;
+
+       sg_init_one(sg, data, count);
+       ret = __send_to_port(port, sg, 1, count, data, false);
+       kfree(data);
+       return ret;
 }
 
 /*
index 4a9e034..4996f4f 100644 (file)
@@ -2326,6 +2326,56 @@ static struct hlist_head *orphan_list[] = {
        NULL,
 };
 
+static void clk_state_subtree(struct clk_core *c)
+{
+       int vdd_level = 0;
+       struct clk_core *child;
+
+       if (!c)
+               return;
+
+       if (c->vdd_class) {
+               vdd_level = clk_find_vdd_level(c, c->rate);
+               if (vdd_level < 0)
+                       vdd_level = 0;
+       }
+
+       trace_clk_state(c->name, c->prepare_count, c->enable_count,
+                                               c->rate, vdd_level);
+
+       hlist_for_each_entry(child, &c->children, child_node)
+               clk_state_subtree(child);
+}
+
+static int clk_state_show(struct seq_file *s, void *data)
+{
+       struct clk_core *c;
+       struct hlist_head **lists = (struct hlist_head **)s->private;
+
+       clk_prepare_lock();
+
+       for (; *lists; lists++)
+               hlist_for_each_entry(c, *lists, child_node)
+                       clk_state_subtree(c);
+
+       clk_prepare_unlock();
+
+       return 0;
+}
+
+
+static int clk_state_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, clk_state_show, inode->i_private);
+}
+
+static const struct file_operations clk_state_fops = {
+       .open           = clk_state_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
                                 int level)
 {
@@ -3002,6 +3052,11 @@ static int __init clk_debug_init(void)
        if (!d)
                return -ENOMEM;
 
+       d = debugfs_create_file("trace_clocks", S_IRUGO, rootdir, &all_lists,
+                               &clk_state_fops);
+       if (!d)
+               return -ENOMEM;
+
        mutex_lock(&clk_debug_lock);
        hlist_for_each_entry(core, &clk_debug_list, debug_node)
                clk_debug_create_one(core, rootdir);
index bcda6f3..bca8ada 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1308,6 +1308,7 @@ static int cpu_clock_8996_driver_probe(struct platform_device *pdev)
        unsigned long pwrclrate, perfclrate, cbfrate;
        int pvs_ver = 0;
        u32 pte_efuse;
+       u32 clk_rate;
        char perfclspeedbinstr[] = "qcom,perfcl-speedbinXX-vXX";
        char pwrclspeedbinstr[] = "qcom,pwrcl-speedbinXX-vXX";
        char cbfspeedbinstr[] = "qcom,cbf-speedbinXX-vXX";
@@ -1435,6 +1436,18 @@ static int cpu_clock_8996_driver_probe(struct platform_device *pdev)
        clk_prepare_enable(&pwrcl_alt_pll.c);
        clk_prepare_enable(&cbf_pll.c);
 
+       /* Override the existing ealry boot frequency for power cluster */
+       ret = of_property_read_u32(pdev->dev.of_node,
+                               "qcom,pwrcl-early-boot-freq", &clk_rate);
+       if (!ret)
+               pwrcl_early_boot_rate = clk_rate;
+
+       /* Override the existing ealry boot frequency for perf cluster */
+       ret = of_property_read_u32(pdev->dev.of_node,
+                               "qcom,perfcl-early-boot-freq", &clk_rate);
+       if (!ret)
+               perfcl_early_boot_rate = clk_rate;
+
        /* Set the early boot rate. This may also switch us to the ACD leg */
        clk_set_rate(&pwrcl_clk.c, pwrcl_early_boot_rate);
        clk_set_rate(&perfcl_clk.c, perfcl_early_boot_rate);
@@ -1450,6 +1463,7 @@ static struct of_device_id match_table[] = {
        { .compatible = "qcom,cpu-clock-8996" },
        { .compatible = "qcom,cpu-clock-8996-v3" },
        { .compatible = "qcom,cpu-clock-8996-pro" },
+       { .compatible = "qcom,cpu-clock-8996-auto" },
        {}
 };
 
@@ -1499,6 +1513,9 @@ module_exit(cpu_clock_8996_exit);
 #define HF_MUX_SEL_LF_MUX 0x1
 #define LF_MUX_SEL_ALT_PLL 0x1
 
+#define PWRCL_EARLY_BOOT_RATE 1286400000
+#define PERFCL_EARLY_BOOT_RATE 1363200000
+
 static int use_alt_pll;
 module_param(use_alt_pll, int, 0444);
 
@@ -1537,6 +1554,12 @@ int __init cpu_clock_8996_early_init(void)
                cpu_clocks_v3 = true;
                cpu_clocks_pro = true;
        } else if (of_find_compatible_node(NULL, NULL,
+                                       "qcom,cpu-clock-8996-auto")) {
+               cpu_clocks_v3 = true;
+               cpu_clocks_pro = true;
+               pwrcl_early_boot_rate = PWRCL_EARLY_BOOT_RATE;
+               perfcl_early_boot_rate = PERFCL_EARLY_BOOT_RATE;
+       } else if (of_find_compatible_node(NULL, NULL,
                                         "qcom,cpu-clock-8996-v3")) {
                cpu_clocks_v3 = true;
        } else if (!of_find_compatible_node(NULL, NULL,
index e93e9c4..6dd2cf8 100644 (file)
@@ -3670,14 +3670,6 @@ static int msm_gcc_8996_probe(struct platform_device *pdev)
        regval |= BIT(21);
        writel_relaxed(regval, virt_base + GCC_APCS_CLOCK_BRANCH_ENA_VOTE);
 
-       /*
-        * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
-        * turned off by hardware during certain apps low power modes.
-        */
-       regval = readl_relaxed(virt_base + GCC_APCS_CLOCK_SLEEP_ENA_VOTE);
-       regval |= BIT(21);
-       writel_relaxed(regval, virt_base + GCC_APCS_CLOCK_SLEEP_ENA_VOTE);
-
        vdd_dig.vdd_uv[1] = RPM_REGULATOR_CORNER_SVS_KRAIT;
        vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
        if (IS_ERR(vdd_dig.regulator[0])) {
index 69d4a13..53e6145 100644 (file)
@@ -278,7 +278,8 @@ static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
                        /* Try to run it through DECO0 */
                        ret = run_descriptor_deco0(ctrldev, desc, &status);
 
-                       if (ret || status) {
+                       if (ret ||
+                           (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
                                dev_err(ctrldev,
                                        "Failed to deinstantiate RNG4 SH%d\n",
                                        sh_idx);
index 1e5f35d..26f69fa 100644 (file)
@@ -179,26 +179,48 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
        struct device *dev = mdm->dev;
        int ret;
        bool graceful_shutdown = false;
+       u32 status, err_fatal;
 
        switch (cmd) {
        case ESOC_PWR_ON:
+               if (esoc->auto_boot) {
+                       /*
+                        * If esoc has already booted, we would have missed
+                        * status change interrupt. Read status and err_fatal
+                        * signals to arrive at the state of esoc.
+                        */
+                       esoc->clink_ops->get_status(&status, esoc);
+                       esoc->clink_ops->get_err_fatal(&err_fatal, esoc);
+                       if (err_fatal)
+                               return -EIO;
+                       if (status && !mdm->ready) {
+                               mdm->ready = true;
+                               esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc);
+                       }
+               }
                gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
-               mdm_enable_irqs(mdm);
                mdm->init = 1;
                mdm_do_first_power_on(mdm);
+               mdm_enable_irqs(mdm);
                break;
        case ESOC_PWR_OFF:
                mdm_disable_irqs(mdm);
                mdm->debug = 0;
                mdm->ready = false;
                mdm->trig_cnt = 0;
+               if (esoc->primary)
+                       break;
                graceful_shutdown = true;
-               ret = sysmon_send_shutdown(&esoc->subsys);
-               if (ret) {
-                       dev_err(mdm->dev, "sysmon shutdown fail, ret = %d\n",
-                                                                       ret);
-                       graceful_shutdown = false;
-                       goto force_poff;
+               if (!esoc->userspace_handle_shutdown) {
+                       ret = sysmon_send_shutdown(&esoc->subsys);
+                       if (ret) {
+                               dev_err(mdm->dev,
+                                "sysmon shutdown fail, ret = %d\n", ret);
+                               graceful_shutdown = false;
+                               goto force_poff;
+                       }
+               } else {
+                       esoc_clink_queue_request(ESOC_REQ_SEND_SHUTDOWN, esoc);
                }
                dev_dbg(mdm->dev, "Waiting for status gpio go low\n");
                status_down = false;
@@ -228,12 +250,17 @@ force_poff:
                                esoc->subsys.sysmon_shutdown_ret);
                }
 
+               if (esoc->primary)
+                       break;
                /*
                 * Force a shutdown of the mdm. This is required in order
                 * to prevent the mdm from immediately powering back on
-                * after the shutdown
+                * after the shutdown. Avoid setting status to 0, if line is
+                * monitored by multiple mdms(might be wrongly interpreted as
+                * a primary crash).
                 */
-               gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
+               if (esoc->statusline_not_a_powersource == false)
+                       gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
                esoc_clink_queue_request(ESOC_REQ_SHUTDOWN, esoc);
                mdm_power_down(mdm);
                mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG);
@@ -249,9 +276,12 @@ force_poff:
                 */
                mdm->ready = false;
                cancel_delayed_work(&mdm->mdm2ap_status_check_work);
-               gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
-               dev_dbg(mdm->dev, "set ap2mdm errfatal to force reset\n");
-               msleep(mdm->ramdump_delay_ms);
+               if (!mdm->esoc->auto_boot) {
+                       gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
+                       dev_dbg(mdm->dev,
+                               "set ap2mdm errfatal to force reset\n");
+                       msleep(mdm->ramdump_delay_ms);
+               }
                break;
        case ESOC_EXE_DEBUG:
                mdm->debug = 1;
@@ -378,6 +408,8 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc)
                status_down = false;
                dev_dbg(dev, "signal apq err fatal for graceful restart\n");
                gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
+               if (esoc->primary)
+                       break;
                timeout = local_clock();
                do_div(timeout, NSEC_PER_MSEC);
                timeout += MDM_MODEM_TIMEOUT;
@@ -420,7 +452,8 @@ static irqreturn_t mdm_errfatal(int irq, void *dev_id)
                goto mdm_pwroff_irq;
        esoc = mdm->esoc;
        dev_err(dev, "%s: mdm sent errfatal interrupt\n",
-                                        __func__);
+                                       __func__);
+       subsys_set_crash_status(esoc->subsys_dev, true);
        /* disable irq ?*/
        esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc);
        return IRQ_HANDLED;
@@ -441,11 +474,26 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
                return IRQ_HANDLED;
        dev = mdm->dev;
        esoc = mdm->esoc;
+       /*
+        * On auto boot devices, there is a possibility of receiving
+        * status change interrupt before esoc_clink structure is
+        * initialized. Ignore them.
+        */
+       if (!esoc)
+               return IRQ_HANDLED;
        value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS));
        if (value == 0 && mdm->ready) {
                dev_err(dev, "unexpected reset external modem\n");
+               subsys_set_crash_status(esoc->subsys_dev, true);
                esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc);
        } else if (value == 1) {
+               /*
+                * In auto_boot cases, bailout early if mdm
+                * is up already.
+                */
+               if (esoc->auto_boot && mdm->ready)
+                       return IRQ_HANDLED;
+
                cancel_delayed_work(&mdm->mdm2ap_status_check_work);
                dev_dbg(dev, "status = 1: mdm is now ready\n");
                mdm->ready = true;
@@ -453,6 +501,8 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
                queue_work(mdm->mdm_queue, &mdm->mdm_status_work);
                if (mdm->get_restart_reason)
                        queue_work(mdm->mdm_queue, &mdm->restart_reason_work);
+               if (esoc->auto_boot)
+                       esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc);
        }
        return IRQ_HANDLED;
 }
@@ -481,7 +531,7 @@ static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int mdm_get_status(u32 *status, struct esoc_clink *esoc)
+static void mdm_get_status(u32 *status, struct esoc_clink *esoc)
 {
        struct mdm_ctrl *mdm = get_esoc_clink_data(esoc);
 
@@ -489,7 +539,16 @@ static int mdm_get_status(u32 *status, struct esoc_clink *esoc)
                *status = 0;
        else
                *status = 1;
-       return 0;
+}
+
+static void mdm_get_err_fatal(u32 *status, struct esoc_clink *esoc)
+{
+       struct mdm_ctrl *mdm = get_esoc_clink_data(esoc);
+
+       if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)) == 0)
+               *status = 0;
+       else
+               *status = 1;
 }
 
 static void mdm_configure_debug(struct mdm_ctrl *mdm)
@@ -573,13 +632,21 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
                                                &mdm->ramdump_delay_ms);
        if (ret)
                mdm->ramdump_delay_ms = DEF_RAMDUMP_DELAY;
-       /* Multilple gpio_request calls are allowed */
+       /*
+        * In certain scenarios, multiple esoc devices are monitoring
+        * same AP2MDM_STATUS line. But only one of them will have a
+        * successful gpio_request call. Initialize gpio only if request
+        * succeeds.
+        */
        if (gpio_request(MDM_GPIO(mdm, AP2MDM_STATUS), "AP2MDM_STATUS"))
                dev_err(dev, "Failed to configure AP2MDM_STATUS gpio\n");
-       /* Multilple gpio_request calls are allowed */
+       else
+               gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
        if (gpio_request(MDM_GPIO(mdm, AP2MDM_ERRFATAL), "AP2MDM_ERRFATAL"))
                dev_err(dev, "%s Failed to configure AP2MDM_ERRFATAL gpio\n",
                           __func__);
+       else
+               gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
        if (gpio_request(MDM_GPIO(mdm, MDM2AP_STATUS), "MDM2AP_STATUS")) {
                dev_err(dev, "%s Failed to configure MDM2AP_STATUS gpio\n",
                           __func__);
@@ -612,9 +679,6 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
                }
        }
 
-       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
-       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
-
        if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_CHNLRDY)))
                gpio_direction_output(MDM_GPIO(mdm, AP2MDM_CHNLRDY), 0);
 
@@ -748,6 +812,7 @@ static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
                dev_err(mdm->dev, "cannot allocate esoc device\n");
                return PTR_ERR(esoc);
        }
+       esoc->pdev = pdev;
        mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
        if (!mdm->mdm_queue) {
                dev_err(mdm->dev, "could not create mdm_queue\n");
@@ -818,6 +883,7 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
                dev_err(mdm->dev, "cannot allocate esoc device\n");
                return PTR_ERR(esoc);
        }
+       esoc->pdev = pdev;
        mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
        if (!mdm->mdm_queue) {
                dev_err(mdm->dev, "could not create mdm_queue\n");
@@ -888,6 +954,84 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
        return 0;
 }
 
+static int mdm9x45_setup_hw(struct mdm_ctrl *mdm,
+                                       const struct mdm_ops *ops,
+                                       struct platform_device *pdev)
+{
+       int ret;
+       struct esoc_clink *esoc;
+       const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
+       const struct mdm_pon_ops *pon_ops = ops->pon_ops;
+
+       mdm->dev = &pdev->dev;
+       mdm->pon_ops = pon_ops;
+       esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
+       if (IS_ERR_OR_NULL(esoc)) {
+               dev_err(mdm->dev, "cannot allocate esoc device\n");
+               return PTR_ERR(esoc);
+       }
+       esoc->pdev = pdev;
+       mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+       if (!mdm->mdm_queue) {
+               dev_err(mdm->dev, "could not create mdm_queue\n");
+               return -ENOMEM;
+       }
+       mdm->irq_mask = 0;
+       mdm->ready = false;
+       ret = mdm_dt_parse_gpios(mdm);
+       if (ret)
+               return ret;
+       dev_err(mdm->dev, "parsing gpio done\n");
+       ret = mdm_pon_dt_init(mdm);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "pon dt init done\n");
+       ret = mdm_pinctrl_init(mdm);
+       if (ret)
+               return ret;
+       dev_err(mdm->dev, "pinctrl init done\n");
+       ret = mdm_pon_setup(mdm);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "pon setup done\n");
+       ret = mdm_configure_ipc(mdm, pdev);
+       if (ret)
+               return ret;
+       mdm_configure_debug(mdm);
+       dev_err(mdm->dev, "ipc configure done\n");
+       esoc->name = MDM9x45_LABEL;
+       esoc->link_name = MDM9x45_PCIE;
+       esoc->clink_ops = clink_ops;
+       esoc->parent = mdm->dev;
+       esoc->owner = THIS_MODULE;
+       esoc->np = pdev->dev.of_node;
+
+       esoc->auto_boot = of_property_read_bool(esoc->np,
+                                               "qcom,mdm-auto-boot");
+       esoc->statusline_not_a_powersource = of_property_read_bool(esoc->np,
+                               "qcom,mdm-statusline-not-a-powersource");
+       esoc->userspace_handle_shutdown = of_property_read_bool(esoc->np,
+                               "qcom,mdm-userspace-handle-shutdown");
+       set_esoc_clink_data(esoc, mdm);
+       ret = esoc_clink_register(esoc);
+       if (ret) {
+               dev_err(mdm->dev, "esoc registration failed\n");
+               return ret;
+       }
+       dev_dbg(mdm->dev, "esoc registration done\n");
+       init_completion(&mdm->debug_done);
+       INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
+       INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
+       INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
+       mdm->get_restart_reason = false;
+       mdm->debug_fail = false;
+       mdm->esoc = esoc;
+       mdm->init = 0;
+       if (esoc->auto_boot)
+               gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
+       return 0;
+}
+
 static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
                                        const struct mdm_ops *ops,
                                        struct platform_device *pdev)
@@ -906,6 +1050,7 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
                dev_err(mdm->dev, "cannot allocate esoc device\n");
                return PTR_ERR(esoc);
        }
+       esoc->pdev = pdev;
        mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
        if (!mdm->mdm_queue) {
                dev_err(mdm->dev, "could not create mdm_queue\n");
@@ -963,9 +1108,86 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
        return 0;
 }
 
+static int apq8096_setup_hw(struct mdm_ctrl *mdm,
+                                       const struct mdm_ops *ops,
+                                       struct platform_device *pdev)
+{
+       int ret;
+       struct device_node *node;
+       struct esoc_clink *esoc;
+       const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
+       const struct mdm_pon_ops *pon_ops = ops->pon_ops;
+
+       mdm->dev = &pdev->dev;
+       mdm->pon_ops = pon_ops;
+       node = pdev->dev.of_node;
+       esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
+       if (IS_ERR_OR_NULL(esoc)) {
+               dev_err(mdm->dev, "cannot allocate esoc device\n");
+               return PTR_ERR(esoc);
+       }
+       esoc->pdev = pdev;
+       mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+       if (!mdm->mdm_queue) {
+               dev_err(mdm->dev, "could not create mdm_queue\n");
+               return -ENOMEM;
+       }
+       mdm->irq_mask = 0;
+       mdm->ready = false;
+       ret = mdm_dt_parse_gpios(mdm);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "parsing gpio done\n");
+       ret = mdm_pon_dt_init(mdm);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "pon dt init done\n");
+       ret = mdm_pinctrl_init(mdm);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "pinctrl init done\n");
+       ret = mdm_pon_setup(mdm);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "pon setup done\n");
+       ret = mdm_configure_ipc(mdm, pdev);
+       if (ret)
+               return ret;
+       dev_dbg(mdm->dev, "ipc configure done\n");
+       esoc->name = APQ8096_LABEL;
+       esoc->link_name = APQ8096_PCIE;
+       esoc->clink_ops = clink_ops;
+       esoc->parent = mdm->dev;
+       esoc->owner = THIS_MODULE;
+       esoc->np = pdev->dev.of_node;
+       esoc->auto_boot = of_property_read_bool(esoc->np,
+                               "qcom,mdm-auto-boot");
+       esoc->primary = of_property_read_bool(esoc->np,
+                               "qcom,mdm-primary");
+       set_esoc_clink_data(esoc, mdm);
+       ret = esoc_clink_register(esoc);
+       if (ret) {
+               dev_err(mdm->dev, "esoc registration failed\n");
+               return ret;
+       }
+       dev_dbg(mdm->dev, "esoc registration done\n");
+       init_completion(&mdm->debug_done);
+       INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
+       INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
+       INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
+       mdm->get_restart_reason = false;
+       mdm->debug_fail = false;
+       mdm->esoc = esoc;
+       mdm->init = 0;
+       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
+       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
+       return 0;
+}
+
 static struct esoc_clink_ops mdm_cops = {
        .cmd_exe = mdm_cmd_exe,
        .get_status = mdm_get_status,
+       .get_err_fatal = mdm_get_err_fatal,
        .notify = mdm_notify,
 };
 
@@ -981,6 +1203,18 @@ static struct mdm_ops mdm9x35_ops = {
        .pon_ops = &mdm9x35_pon_ops,
 };
 
+static struct mdm_ops mdm9x45_ops = {
+       .clink_ops = &mdm_cops,
+       .config_hw = mdm9x45_setup_hw,
+       .pon_ops = &mdm9x45_pon_ops,
+};
+
+static struct mdm_ops apq8096_ops = {
+       .clink_ops = &mdm_cops,
+       .config_hw = apq8096_setup_hw,
+       .pon_ops = &apq8096_pon_ops,
+};
+
 static struct mdm_ops mdm9x55_ops = {
        .clink_ops = &mdm_cops,
        .config_hw = mdm9x55_setup_hw,
@@ -992,8 +1226,12 @@ static const struct of_device_id mdm_dt_match[] = {
                .data = &mdm9x25_ops, },
        { .compatible = "qcom,ext-mdm9x35",
                .data = &mdm9x35_ops, },
+       { .compatible = "qcom,ext-mdm9x45",
+               .data = &mdm9x45_ops, },
        { .compatible = "qcom,ext-mdm9x55",
                .data = &mdm9x55_ops, },
+       { .compatible = "qcom,ext-apq8096",
+               .data = &apq8096_ops, },
        {},
 };
 MODULE_DEVICE_TABLE(of, mdm_dt_match);
index 8697428..9c2c68d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/reboot.h>
+#include <linux/of.h>
 #include "esoc.h"
 #include "mdm-dbg.h"
 
@@ -72,7 +73,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt,
                break;
        case ESOC_UNEXPECTED_RESET:
        case ESOC_ERR_FATAL:
-               if (mdm_drv->mode == CRASH)
+               /*
+                * Modem can crash while we are waiting for boot_done during
+                * a subsystem_get(). Setting mode to CRASH will prevent a
+                * subsequent subsystem_get() from entering poweron ops. Avoid
+                * this by seting mode to CRASH only if device was up and
+                * running.
+                */
+               if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN)
                        return;
                mdm_drv->mode = CRASH;
                queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work);
@@ -161,8 +169,9 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
                                                                subsys);
        struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink);
        const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
+       int timeout = INT_MAX;
 
-       if (!esoc_req_eng_enabled(esoc_clink)) {
+       if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) {
                dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n");
                wait_for_completion(&mdm_drv->req_eng_wait);
        }
@@ -187,8 +196,17 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
                        return ret;
                }
        }
-       wait_for_completion(&mdm_drv->boot_done);
-       if (mdm_drv->boot_fail) {
+
+       /*
+        * In autoboot case, it is possible that we can forever wait for
+        * boot completion, when esoc fails to boot. This is because there
+        * is no helper application which can alert esoc driver about boot
+        * failure. Prevent going to wait forever in such case.
+        */
+       if (esoc_clink->auto_boot)
+               timeout = 10 * HZ;
+       ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout);
+       if (mdm_drv->boot_fail || ret <= 0) {
                dev_err(&esoc_clink->dev, "booting failed\n");
                return -EIO;
        }
@@ -216,10 +234,12 @@ static int mdm_subsys_ramdumps(int want_dumps,
 
 static int mdm_register_ssr(struct esoc_clink *esoc_clink)
 {
-       esoc_clink->subsys.shutdown = mdm_subsys_shutdown;
-       esoc_clink->subsys.ramdump = mdm_subsys_ramdumps;
-       esoc_clink->subsys.powerup = mdm_subsys_powerup;
-       esoc_clink->subsys.crash_shutdown = mdm_crash_shutdown;
+       struct subsys_desc *subsys = &esoc_clink->subsys;
+
+       subsys->shutdown = mdm_subsys_shutdown;
+       subsys->ramdump = mdm_subsys_ramdumps;
+       subsys->powerup = mdm_subsys_powerup;
+       subsys->crash_shutdown = mdm_crash_shutdown;
        return esoc_clink_register_ssr(esoc_clink);
 }
 
@@ -286,6 +306,14 @@ static struct esoc_compat compat_table[] = {
                .name = "MDM9x55",
                .data = NULL,
        },
+       {
+               .name = "MDM9x45",
+               .data = NULL,
+       },
+       {
+               .name = "APQ8096",
+               .data = NULL,
+       },
 };
 
 static struct esoc_drv esoc_ssr_drv = {
index acda064..4ae3b75 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -60,6 +60,29 @@ static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
        return 0;
 }
 
+/* This function can be called from atomic context. */
+static int mdm9x45_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
+{
+       int soft_reset_direction_assert = 0,
+           soft_reset_direction_de_assert = 1;
+
+       if (mdm->soft_reset_inverted) {
+               soft_reset_direction_assert = 1;
+               soft_reset_direction_de_assert = 0;
+       }
+       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+                       soft_reset_direction_assert);
+       /*
+        * Allow PS hold assert to be detected
+        */
+       if (!atomic)
+               usleep_range(1000000, 1005000);
+       else
+               mdelay(1000);
+       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+                       soft_reset_direction_de_assert);
+       return 0;
+}
 
 static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
 {
@@ -68,6 +91,9 @@ static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
        struct device *dev = mdm->dev;
 
        dev_dbg(dev, "Powering on modem for the first time\n");
+       if (mdm->esoc->auto_boot)
+               return 0;
+
        mdm_toggle_soft_reset(mdm, false);
        /* Add a delay to allow PON sequence to complete*/
        msleep(50);
@@ -132,8 +158,31 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm)
        return 0;
 }
 
+static int mdm9x45_power_down(struct mdm_ctrl *mdm)
+{
+       int soft_reset_direction_assert = 0,
+           soft_reset_direction_de_assert = 1;
+
+       if (mdm->soft_reset_inverted) {
+               soft_reset_direction_assert = 1;
+               soft_reset_direction_de_assert = 0;
+       }
+       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+                       soft_reset_direction_assert);
+       /*
+        * Allow PS hold assert to be detected
+        */
+       msleep(3003);
+       gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+                       soft_reset_direction_de_assert);
+       return 0;
+}
+
 static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
 {
+       if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET)))
+               return;
+
        dev_dbg(mdm->dev, "Triggering mdm cold reset");
        gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
                        !!mdm->soft_reset_inverted);
@@ -152,6 +201,11 @@ static void mdm9x55_cold_reset(struct mdm_ctrl *mdm)
                        !mdm->soft_reset_inverted);
 }
 
+static int apq8096_pon_dt_init(struct mdm_ctrl *mdm)
+{
+       return 0;
+}
+
 static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
 {
        int val;
@@ -183,6 +237,21 @@ static int mdm4x_pon_setup(struct mdm_ctrl *mdm)
        return 0;
 }
 
+/* This function can be called from atomic context. */
+static int apq8096_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
+{
+       return 0;
+}
+
+static int apq8096_power_down(struct mdm_ctrl *mdm)
+{
+       return 0;
+}
+
+static void apq8096_cold_reset(struct mdm_ctrl *mdm)
+{
+}
+
 struct mdm_pon_ops mdm9x25_pon_ops = {
        .pon = mdm4x_do_first_power_on,
        .soft_reset = mdm4x_toggle_soft_reset,
@@ -203,8 +272,8 @@ struct mdm_pon_ops mdm9x35_pon_ops = {
 
 struct mdm_pon_ops mdm9x45_pon_ops = {
        .pon = mdm4x_do_first_power_on,
-       .soft_reset = mdm4x_toggle_soft_reset,
-       .poff_force = mdm4x_power_down,
+       .soft_reset = mdm9x45_toggle_soft_reset,
+       .poff_force = mdm9x45_power_down,
        .cold_reset = mdm4x_cold_reset,
        .dt_init = mdm4x_pon_dt_init,
        .setup = mdm4x_pon_setup,
@@ -218,3 +287,12 @@ struct mdm_pon_ops mdm9x55_pon_ops = {
        .dt_init = mdm4x_pon_dt_init,
        .setup = mdm4x_pon_setup,
 };
+
+struct mdm_pon_ops apq8096_pon_ops = {
+       .pon = mdm4x_do_first_power_on,
+       .soft_reset = apq8096_toggle_soft_reset,
+       .poff_force = apq8096_power_down,
+       .cold_reset = apq8096_cold_reset,
+       .dt_init = apq8096_pon_dt_init,
+       .setup = mdm4x_pon_setup,
+};
index ac81172..9343e49 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -37,6 +37,8 @@
 #define MDM9x45_PCIE                   "PCIe"
 #define MDM9x55_LABEL                  "MDM9x55"
 #define MDM9x55_PCIE                   "PCIe"
+#define APQ8096_LABEL                  "APQ8096"
+#define APQ8096_PCIE                   "PCIe"
 #define MDM2AP_STATUS_TIMEOUT_MS       120000L
 #define MDM_MODEM_TIMEOUT              3000
 #define DEF_RAMDUMP_TIMEOUT            120000
@@ -153,4 +155,5 @@ extern struct mdm_pon_ops mdm9x25_pon_ops;
 extern struct mdm_pon_ops mdm9x35_pon_ops;
 extern struct mdm_pon_ops mdm9x45_pon_ops;
 extern struct mdm_pon_ops mdm9x55_pon_ops;
+extern struct mdm_pon_ops apq8096_pon_ops;
 #endif
index 755fb24..ee54908 100644 (file)
@@ -49,6 +49,7 @@ struct esoc_eng {
  * @link_info: additional info about the physical link.
  * @parent: parent device.
  * @dev: device for userspace interface.
+ * @pdev: platform device to interface with SSR driver.
  * @id: id of the external device.
  * @owner: owner of the device.
  * @clink_ops: control operations for the control link
@@ -59,6 +60,12 @@ struct esoc_eng {
  * @subsys_desc: descriptor for subsystem restart
  * @subsys_dev: ssr device handle.
  * @np: device tree node for esoc_clink.
+ * @auto_boot: boots independently.
+ * @primary: primary esoc controls(reset/poweroff) all secondary
+ *      esocs, but not otherway around.
+ * @statusline_not_a_powersource: True if status line to esoc is not a
+ *                             power source.
+ * @userspace_handle_shutdown: True if user space handles shutdown requests.
  */
 struct esoc_clink {
        const char *name;
@@ -66,6 +73,7 @@ struct esoc_clink {
        const char *link_info;
        struct device *parent;
        struct device dev;
+       struct platform_device *pdev;
        unsigned int id;
        struct module *owner;
        const struct esoc_clink_ops const *clink_ops;
@@ -77,17 +85,23 @@ struct esoc_clink {
        struct subsys_desc subsys;
        struct subsys_device *subsys_dev;
        struct device_node *np;
+       bool auto_boot;
+       bool primary;
+       bool statusline_not_a_powersource;
+       bool userspace_handle_shutdown;
 };
 
 /**
  * struct esoc_clink_ops: Operations to control external soc
  * @cmd_exe: Execute control command
  * @get_status: Get current status, or response to previous command
+ * @get_err_fatal: Get status of err fatal signal
  * @notify_esoc: notify external soc of events
  */
 struct esoc_clink_ops {
        int (*cmd_exe)(enum esoc_cmd cmd, struct esoc_clink *dev);
-       int (*get_status)(u32 *status, struct esoc_clink *dev);
+       void (*get_status)(u32 *status, struct esoc_clink *dev);
+       void (*get_err_fatal)(u32 *status, struct esoc_clink *dev);
        void (*notify)(enum esoc_notify notify, struct esoc_clink *dev);
 };
 
index f925607..94f5276 100644 (file)
@@ -189,7 +189,7 @@ int esoc_clink_register_ssr(struct esoc_clink *esoc_clink)
        snprintf(subsys_name, len, "esoc%d", esoc_clink->id);
        esoc_clink->subsys.name = subsys_name;
        esoc_clink->dev.of_node = esoc_clink->np;
-       esoc_clink->subsys.dev = &esoc_clink->dev;
+       esoc_clink->subsys.dev = &esoc_clink->pdev->dev;
        esoc_clink->subsys_dev = subsys_register(&esoc_clink->subsys);
        if (IS_ERR_OR_NULL(esoc_clink->subsys_dev)) {
                dev_err(&esoc_clink->dev, "failed to register ssr node\n");
index bbe1d24..a1e7a52 100644 (file)
@@ -224,9 +224,11 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
                clink_ops->notify(esoc_cmd, esoc_clink);
                break;
        case ESOC_GET_STATUS:
-               err = clink_ops->get_status(&status, esoc_clink);
-               if (err)
-                       return err;
+               clink_ops->get_status(&status, esoc_clink);
+               put_user(status, (unsigned int __user *)uarg);
+               break;
+       case ESOC_GET_ERR_FATAL:
+               clink_ops->get_err_fatal(&status, esoc_clink);
                put_user(status, (unsigned int __user *)uarg);
                break;
        case ESOC_WAIT_FOR_CRASH:
index fb9f647..5044f22 100644 (file)
@@ -1159,7 +1159,7 @@ struct intel_gen6_power_mgmt {
        struct intel_rps_client semaphores, mmioflips;
 
        /* manual wa residency calculations */
-       struct intel_rps_ei up_ei, down_ei;
+       struct intel_rps_ei ei;
 
        /*
         * Protects RPS/RC6 register access and PCU communication.
index 0f42a27..b7b0a38 100644 (file)
@@ -994,68 +994,51 @@ static void vlv_c0_read(struct drm_i915_private *dev_priv,
        ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
 }
 
-static bool vlv_c0_above(struct drm_i915_private *dev_priv,
-                        const struct intel_rps_ei *old,
-                        const struct intel_rps_ei *now,
-                        int threshold)
-{
-       u64 time, c0;
-       unsigned int mul = 100;
-
-       if (old->cz_clock == 0)
-               return false;
-
-       if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
-               mul <<= 8;
-
-       time = now->cz_clock - old->cz_clock;
-       time *= threshold * dev_priv->czclk_freq;
-
-       /* Workload can be split between render + media, e.g. SwapBuffers
-        * being blitted in X after being rendered in mesa. To account for
-        * this we need to combine both engines into our activity counter.
-        */
-       c0 = now->render_c0 - old->render_c0;
-       c0 += now->media_c0 - old->media_c0;
-       c0 *= mul * VLV_CZ_CLOCK_TO_MILLI_SEC;
-
-       return c0 >= time;
-}
-
 void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
 {
-       vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
-       dev_priv->rps.up_ei = dev_priv->rps.down_ei;
+       memset(&dev_priv->rps.ei, 0, sizeof(dev_priv->rps.ei));
 }
 
 static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
 {
+       const struct intel_rps_ei *prev = &dev_priv->rps.ei;
        struct intel_rps_ei now;
        u32 events = 0;
 
-       if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0)
+       if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
                return 0;
 
        vlv_c0_read(dev_priv, &now);
        if (now.cz_clock == 0)
                return 0;
 
-       if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
-               if (!vlv_c0_above(dev_priv,
-                                 &dev_priv->rps.down_ei, &now,
-                                 dev_priv->rps.down_threshold))
-                       events |= GEN6_PM_RP_DOWN_THRESHOLD;
-               dev_priv->rps.down_ei = now;
-       }
+       if (prev->cz_clock) {
+               u64 time, c0;
+               unsigned int mul;
 
-       if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
-               if (vlv_c0_above(dev_priv,
-                                &dev_priv->rps.up_ei, &now,
-                                dev_priv->rps.up_threshold))
-                       events |= GEN6_PM_RP_UP_THRESHOLD;
-               dev_priv->rps.up_ei = now;
+               mul = VLV_CZ_CLOCK_TO_MILLI_SEC * 100; /* scale to threshold% */
+               if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
+                       mul <<= 8;
+
+               time = now.cz_clock - prev->cz_clock;
+               time *= dev_priv->czclk_freq;
+
+               /* Workload can be split between render + media,
+                * e.g. SwapBuffers being blitted in X after being rendered in
+                * mesa. To account for this we need to combine both engines
+                * into our activity counter.
+                */
+               c0 = now.render_c0 - prev->render_c0;
+               c0 += now.media_c0 - prev->media_c0;
+               c0 *= mul;
+
+               if (c0 > time * dev_priv->rps.up_threshold)
+                       events = GEN6_PM_RP_UP_THRESHOLD;
+               else if (c0 < time * dev_priv->rps.down_threshold)
+                       events = GEN6_PM_RP_DOWN_THRESHOLD;
        }
 
+       dev_priv->rps.ei = now;
        return events;
 }
 
@@ -4390,7 +4373,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        /* Let's track the enabled rps events */
        if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
                /* WaGsvRC0ResidencyMethod:vlv */
-               dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
+               dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
        else
                dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
index e7c1851..fd4690e 100644 (file)
@@ -4376,6 +4376,12 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
                break;
        }
 
+       /* When byt can survive without system hang with dynamic
+        * sw freq adjustments, this restriction can be lifted.
+        */
+       if (IS_VALLEYVIEW(dev_priv))
+               goto skip_hw_write;
+
        I915_WRITE(GEN6_RP_UP_EI,
                GT_INTERVAL_FROM_US(dev_priv, ei_up));
        I915_WRITE(GEN6_RP_UP_THRESHOLD,
@@ -4394,6 +4400,7 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
                    GEN6_RP_UP_BUSY_AVG |
                    GEN6_RP_DOWN_IDLE_AVG);
 
+skip_hw_write:
        dev_priv->rps.power = new_power;
        dev_priv->rps.up_threshold = threshold_up;
        dev_priv->rps.down_threshold = threshold_down;
@@ -4404,8 +4411,9 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
 {
        u32 mask = 0;
 
+       /* We use UP_EI_EXPIRED interupts for both up/down in manual mode */
        if (val > dev_priv->rps.min_freq_softlimit)
-               mask |= GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
+               mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
        if (val < dev_priv->rps.max_freq_softlimit)
                mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
 
@@ -4509,7 +4517,7 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv)
 {
        mutex_lock(&dev_priv->rps.hw_lock);
        if (dev_priv->rps.enabled) {
-               if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
+               if (dev_priv->pm_rps_events & GEN6_PM_RP_UP_EI_EXPIRED)
                        gen6_rps_reset_ei(dev_priv);
                I915_WRITE(GEN6_PMINTRMSK,
                           gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
index 3d0617d..f3a8a84 100644 (file)
@@ -49,6 +49,7 @@ msm_drm-y := \
        sde/sde_vbif.o \
        sde_dbg_evtlog.o \
        sde_io_util.o \
+       dba_bridge.o \
        sde_edid_parser.o
 
 # use drm gpu driver only if qcom_kgsl driver not available
index c4f886f..a417e42 100644 (file)
@@ -466,6 +466,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        struct msm_gpu *gpu;
        struct msm_drm_private *priv = dev->dev_private;
        struct platform_device *pdev = priv->gpu_pdev;
+       struct msm_gpu_config a3xx_config = { 0 };
        int ret;
 
        if (!pdev) {
@@ -491,7 +492,13 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        adreno_gpu->registers = a3xx_registers;
        adreno_gpu->reg_offsets = a3xx_register_offsets;
 
-       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
+       a3xx_config.ioname = MSM_GPU_DEFAULT_IONAME;
+       a3xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME;
+       a3xx_config.nr_rings = 1;
+       a3xx_config.va_start = 0x300000;
+       a3xx_config.va_end = 0xffffffff;
+
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a3xx_config);
        if (ret)
                goto fail;
 
index 534a7c3..069823f 100644 (file)
@@ -543,6 +543,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
        struct msm_gpu *gpu;
        struct msm_drm_private *priv = dev->dev_private;
        struct platform_device *pdev = priv->gpu_pdev;
+       struct msm_gpu_config a4xx_config = { 0 };
        int ret;
 
        if (!pdev) {
@@ -568,7 +569,13 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
        adreno_gpu->registers = a4xx_registers;
        adreno_gpu->reg_offsets = a4xx_register_offsets;
 
-       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
+       a4xx_config.ioname = MSM_GPU_DEFAULT_IONAME;
+       a4xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME;
+       a4xx_config.nr_rings = 1;
+       a4xx_config.va_start = 0x300000;
+       a4xx_config.va_end = 0xffffffff;
+
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a4xx_config);
        if (ret)
                goto fail;
 
index 9ceef8f..de2ee1f 100644 (file)
@@ -1163,7 +1163,7 @@ static const u32 a5xx_registers[] = {
        0xe9c0, 0xe9c7, 0xe9d0, 0xe9d1, 0xea00, 0xea01, 0xea10, 0xea1c,
        0xea40, 0xea68, 0xea80, 0xea80, 0xea82, 0xeaa3, 0xeaa5, 0xeac2,
        0xeb80, 0xeb8f, 0xebb0, 0xebb0, 0xec00, 0xec05, 0xec08, 0xece9,
-       0xecf0, 0xecf0, 0xf400, 0xf400, 0xf800, 0xf807,
+       0xecf0, 0xecf0, 0xf800, 0xf807,
        ~0
 };
 
@@ -1368,6 +1368,7 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
        struct a5xx_gpu *a5xx_gpu = NULL;
        struct adreno_gpu *adreno_gpu;
        struct msm_gpu *gpu;
+       struct msm_gpu_config a5xx_config = { 0 };
        int ret;
 
        if (!pdev) {
@@ -1391,7 +1392,20 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
        /* Check the efuses for some configuration */
        a5xx_efuses_read(pdev, adreno_gpu);
 
-       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4);
+       a5xx_config.ioname = MSM_GPU_DEFAULT_IONAME;
+       a5xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME;
+
+       /* Set the number of rings to 4 - yay preemption */
+       a5xx_config.nr_rings = 4;
+
+       /*
+        * Set the user domain range to fall into the TTBR1 region for global
+        * objects
+        */
+       a5xx_config.va_start = 0x800000000;
+       a5xx_config.va_end = 0x8ffffffff;
+
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a5xx_config);
        if (ret) {
                a5xx_destroy(&(a5xx_gpu->base.base));
                return ERR_PTR(ret);
index 5a2edb0..690e6f5 100644 (file)
@@ -733,6 +733,35 @@ static void a5xx_snapshot_indexed_registers(struct msm_gpu *gpu,
        }
 }
 
+static void a5xx_snapshot_preemption(struct msm_gpu *gpu, struct msm_snapshot
+               *snapshot)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
+       struct msm_snapshot_gpu_object header = {
+               .type = SNAPSHOT_GPU_OBJECT_GLOBAL,
+               .size = A5XX_PREEMPT_RECORD_SIZE >> 2,
+               .pt_base = 0,
+       };
+       int index;
+
+       if (gpu->nr_rings <= 1)
+               return;
+
+       for (index = 0; index < gpu->nr_rings; index++) {
+
+               header.gpuaddr = a5xx_gpu->preempt_iova[index];
+
+               if (!SNAPSHOT_HEADER(snapshot, header,
+                       SNAPSHOT_SECTION_GPU_OBJECT_V2,
+                       A5XX_PREEMPT_RECORD_SIZE >> 2))
+                       return;
+
+               SNAPSHOT_MEMCPY(snapshot, a5xx_gpu->preempt[index],
+                               A5XX_PREEMPT_RECORD_SIZE);
+       }
+}
+
 int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot)
 {
        struct crashdump crashdump = { 0 };
@@ -787,6 +816,9 @@ int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot)
        /* CP MERCIU */
        a5xx_snapshot_cp_merciu(gpu, snapshot);
 
+       /* Preemption records*/
+       a5xx_snapshot_preemption(gpu, snapshot);
+
        crashdump_destroy(gpu, &crashdump);
        snapshot->priv = NULL;
 
index 19267b2..9952fa8 100644 (file)
@@ -405,10 +405,6 @@ void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords)
                        ring->gpu->name, ring->id);
 }
 
-static const char *iommu_ports[] = {
-               "gfx3d_user",
-};
-
 /* Read the set of powerlevels */
 static int _adreno_get_pwrlevels(struct msm_gpu *gpu, struct device_node *node)
 {
@@ -524,10 +520,10 @@ static int adreno_of_parse(struct platform_device *pdev, struct msm_gpu *gpu)
 
 int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                struct adreno_gpu *adreno_gpu,
-               const struct adreno_gpu_funcs *funcs, int nr_rings)
+               const struct adreno_gpu_funcs *funcs,
+               struct msm_gpu_config *gpu_config)
 {
        struct adreno_platform_config *config = pdev->dev.platform_data;
-       struct msm_gpu_config adreno_gpu_config  = { 0 };
        struct msm_gpu *gpu = &adreno_gpu->base;
        struct msm_mmu *mmu;
        int ret;
@@ -541,26 +537,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        /* Get the rest of the target configuration from the device tree */
        adreno_of_parse(pdev, gpu);
 
-       adreno_gpu_config.ioname = "kgsl_3d0_reg_memory";
-       adreno_gpu_config.irqname = "kgsl_3d0_irq";
-       adreno_gpu_config.nr_rings = nr_rings;
-
-       adreno_gpu_config.va_start = SZ_16M;
-       adreno_gpu_config.va_end = 0xffffffff;
-
-       if (adreno_gpu->revn >= 500) {
-               /* 5XX targets use a 64 bit region */
-               adreno_gpu_config.va_start = 0x800000000;
-               adreno_gpu_config.va_end = 0x8ffffffff;
-       } else {
-               adreno_gpu_config.va_start = 0x300000;
-               adreno_gpu_config.va_end = 0xffffffff;
-       }
-
-       adreno_gpu_config.nr_rings = nr_rings;
-
        ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
-                       adreno_gpu->info->name, &adreno_gpu_config);
+                       adreno_gpu->info->name, gpu_config);
        if (ret)
                return ret;
 
@@ -580,8 +558,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
        mmu = gpu->aspace->mmu;
        if (mmu) {
-               ret = mmu->funcs->attach(mmu, iommu_ports,
-                               ARRAY_SIZE(iommu_ports));
+               ret = mmu->funcs->attach(mmu, NULL, 0);
                if (ret)
                        return ret;
        }
@@ -722,7 +699,7 @@ static struct adreno_counter_group *get_counter_group(struct msm_gpu *gpu,
                return ERR_PTR(-ENODEV);
 
        if (groupid >= adreno_gpu->nr_counter_groups)
-               return ERR_PTR(-EINVAL);
+               return ERR_PTR(-ENODEV);
 
        return (struct adreno_counter_group *)
                adreno_gpu->counter_groups[groupid];
@@ -745,7 +722,7 @@ u64 adreno_read_counter(struct msm_gpu *gpu, u32 groupid, int counterid)
        struct adreno_counter_group *group =
                get_counter_group(gpu, groupid);
 
-       if (!IS_ERR(group) && group->funcs.read)
+       if (!IS_ERR_OR_NULL(group) && group->funcs.read)
                return group->funcs.read(gpu, group, counterid);
 
        return 0;
@@ -756,6 +733,6 @@ void adreno_put_counter(struct msm_gpu *gpu, u32 groupid, int counterid)
        struct adreno_counter_group *group =
                get_counter_group(gpu, groupid);
 
-       if (!IS_ERR(group) && group->funcs.put)
+       if (!IS_ERR_OR_NULL(group) && group->funcs.put)
                group->funcs.put(gpu, group, counterid);
 }
index 8e8f3e5..3f9bc65 100644 (file)
@@ -257,7 +257,7 @@ struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu);
 
 int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
-               int nr_rings);
+               struct msm_gpu_config *config);
 void adreno_gpu_cleanup(struct adreno_gpu *gpu);
 
 void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot);
diff --git a/drivers/gpu/drm/msm/dba_bridge.c b/drivers/gpu/drm/msm/dba_bridge.c
new file mode 100644 (file)
index 0000000..f933a7f
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <video/msm_dba.h>
+#include "drm_edid.h"
+#include "sde_kms.h"
+#include "dba_bridge.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)    "dba_bridge:[%s] " fmt, __func__
+
+/**
+ * struct dba_bridge - DBA bridge information
+ * @base:               drm_bridge base
+ * @client_name:        Client's name who calls the init
+ * @chip_name:          Bridge chip name
+ * @name:               Bridge chip name
+ * @id:                 Bridge driver index
+ * @display:            Private display handle
+ * @list:               Bridge chip driver list node
+ * @ops:                DBA operation container
+ * @dba_ctx:            DBA context
+ * @mode:               DRM mode info
+ * @hdmi_mode:          HDMI or DVI mode for the sink
+ * @num_of_input_lanes: Number of input lanes in case of DSI/LVDS
+ * @pluggable:          If it's pluggable
+ * @panel_count:        Number of panels attached to this display
+ */
+struct dba_bridge {
+       struct drm_bridge base;
+       char client_name[MSM_DBA_CLIENT_NAME_LEN];
+       char chip_name[MSM_DBA_CHIP_NAME_MAX_LEN];
+       u32 id;
+       void *display;
+       struct list_head list;
+       struct msm_dba_ops ops;
+       void *dba_ctx;
+       struct drm_display_mode mode;
+       bool hdmi_mode;
+       u32 num_of_input_lanes;
+       bool pluggable;
+       u32 panel_count;
+};
+#define to_dba_bridge(x)     container_of((x), struct dba_bridge, base)
+
+static void _dba_bridge_cb(void *data, enum msm_dba_callback_event event)
+{
+       struct dba_bridge *d_bridge = data;
+
+       if (!d_bridge) {
+               SDE_ERROR("Invalid data\n");
+               return;
+       }
+
+       DRM_DEBUG("event: %d\n", event);
+
+       switch (event) {
+       case MSM_DBA_CB_HPD_CONNECT:
+               DRM_DEBUG("HPD CONNECT\n");
+               break;
+       case MSM_DBA_CB_HPD_DISCONNECT:
+               DRM_DEBUG("HPD DISCONNECT\n");
+               break;
+       default:
+               DRM_DEBUG("event:%d is not supported\n", event);
+               break;
+       }
+}
+
+static int _dba_bridge_attach(struct drm_bridge *bridge)
+{
+       struct dba_bridge *d_bridge = to_dba_bridge(bridge);
+       struct msm_dba_reg_info info;
+       int ret = 0;
+
+       if (!bridge) {
+               SDE_ERROR("Invalid params\n");
+               return -EINVAL;
+       }
+
+       memset(&info, 0, sizeof(info));
+       /* initialize DBA registration data */
+       strlcpy(info.client_name, d_bridge->client_name,
+                                       MSM_DBA_CLIENT_NAME_LEN);
+       strlcpy(info.chip_name, d_bridge->chip_name,
+                                       MSM_DBA_CHIP_NAME_MAX_LEN);
+       info.instance_id = d_bridge->id;
+       info.cb = _dba_bridge_cb;
+       info.cb_data = d_bridge;
+
+       /* register client with DBA and get device's ops*/
+       if (IS_ENABLED(CONFIG_MSM_DBA)) {
+               d_bridge->dba_ctx = msm_dba_register_client(&info,
+                                                       &d_bridge->ops);
+               if (IS_ERR_OR_NULL(d_bridge->dba_ctx)) {
+                       SDE_ERROR("dba register failed\n");
+                       ret = PTR_ERR(d_bridge->dba_ctx);
+                       goto error;
+               }
+       } else {
+               SDE_ERROR("DBA not enabled\n");
+               ret = -ENODEV;
+               goto error;
+       }
+
+       DRM_INFO("client:%s bridge:[%s:%d] attached\n",
+               d_bridge->client_name, d_bridge->chip_name, d_bridge->id);
+
+error:
+       return ret;
+}
+
+static void _dba_bridge_pre_enable(struct drm_bridge *bridge)
+{
+       if (!bridge) {
+               SDE_ERROR("Invalid params\n");
+               return;
+       }
+}
+
+static void _dba_bridge_enable(struct drm_bridge *bridge)
+{
+       int rc = 0;
+       struct dba_bridge *d_bridge = to_dba_bridge(bridge);
+       struct msm_dba_video_cfg video_cfg;
+       struct drm_display_mode *mode;
+       struct hdmi_avi_infoframe avi_frame;
+
+       if (!bridge) {
+               SDE_ERROR("Invalid params\n");
+               return;
+       }
+
+       memset(&video_cfg, 0, sizeof(video_cfg));
+       memset(&avi_frame, 0, sizeof(avi_frame));
+       mode = &d_bridge->mode;
+       video_cfg.h_active = mode->hdisplay;
+       video_cfg.v_active = mode->vdisplay;
+       video_cfg.h_front_porch = mode->hsync_start - mode->hdisplay;
+       video_cfg.v_front_porch = mode->vsync_start - mode->vdisplay;
+       video_cfg.h_back_porch = mode->htotal - mode->hsync_end;
+       video_cfg.v_back_porch = mode->vtotal - mode->vsync_end;
+       video_cfg.h_pulse_width = mode->hsync_end - mode->hsync_start;
+       video_cfg.v_pulse_width = mode->vsync_end - mode->vsync_start;
+       video_cfg.pclk_khz = mode->clock;
+       video_cfg.hdmi_mode = d_bridge->hdmi_mode;
+       video_cfg.num_of_input_lanes = d_bridge->num_of_input_lanes;
+
+       SDE_DEBUG(
+               "video=h[%d,%d,%d,%d] v[%d,%d,%d,%d] pclk=%d hdmi=%d lane=%d\n",
+               video_cfg.h_active, video_cfg.h_front_porch,
+               video_cfg.h_pulse_width, video_cfg.h_back_porch,
+               video_cfg.v_active, video_cfg.v_front_porch,
+               video_cfg.v_pulse_width, video_cfg.v_back_porch,
+               video_cfg.pclk_khz, video_cfg.hdmi_mode,
+               video_cfg.num_of_input_lanes);
+
+       rc = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, mode);
+       if (rc) {
+               SDE_ERROR("get avi frame failed ret=%d\n", rc);
+       } else {
+               video_cfg.scaninfo = avi_frame.scan_mode;
+               switch (avi_frame.picture_aspect) {
+               case HDMI_PICTURE_ASPECT_4_3:
+                       video_cfg.ar = MSM_DBA_AR_4_3;
+                       break;
+               case HDMI_PICTURE_ASPECT_16_9:
+                       video_cfg.ar = MSM_DBA_AR_16_9;
+                       break;
+               default:
+                       break;
+               }
+               video_cfg.vic = avi_frame.video_code;
+               DRM_INFO("scaninfo=%d ar=%d vic=%d\n",
+                       video_cfg.scaninfo, video_cfg.ar, video_cfg.vic);
+       }
+
+       if (d_bridge->ops.video_on) {
+               rc = d_bridge->ops.video_on(d_bridge->dba_ctx, true,
+                                               &video_cfg, 0);
+               if (rc)
+                       SDE_ERROR("video on failed ret=%d\n", rc);
+       }
+}
+
+static void _dba_bridge_disable(struct drm_bridge *bridge)
+{
+       int rc = 0;
+       struct dba_bridge *d_bridge = to_dba_bridge(bridge);
+
+       if (!bridge) {
+               SDE_ERROR("Invalid params\n");
+               return;
+       }
+
+       if (d_bridge->ops.video_on) {
+               rc = d_bridge->ops.video_on(d_bridge->dba_ctx, false, NULL, 0);
+               if (rc)
+                       SDE_ERROR("video off failed ret=%d\n", rc);
+       }
+}
+
+static void _dba_bridge_post_disable(struct drm_bridge *bridge)
+{
+       if (!bridge) {
+               SDE_ERROR("Invalid params\n");
+               return;
+       }
+}
+
+static void _dba_bridge_mode_set(struct drm_bridge *bridge,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct dba_bridge *d_bridge = to_dba_bridge(bridge);
+
+       if (!bridge || !mode || !adjusted_mode || !d_bridge) {
+               SDE_ERROR("Invalid params\n");
+               return;
+       } else if (!d_bridge->panel_count) {
+               SDE_ERROR("Panel count is 0\n");
+               return;
+       }
+
+       d_bridge->mode = *adjusted_mode;
+       /* Adjust mode according to number of panels */
+       d_bridge->mode.hdisplay /= d_bridge->panel_count;
+       d_bridge->mode.hsync_start /= d_bridge->panel_count;
+       d_bridge->mode.hsync_end /= d_bridge->panel_count;
+       d_bridge->mode.htotal /= d_bridge->panel_count;
+       d_bridge->mode.clock /= d_bridge->panel_count;
+}
+
+static bool _dba_bridge_mode_fixup(struct drm_bridge *bridge,
+                                 const struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       bool ret = true;
+
+       if (!bridge || !mode || !adjusted_mode) {
+               SDE_ERROR("Invalid params\n");
+               return false;
+       }
+
+       return ret;
+}
+
+static const struct drm_bridge_funcs _dba_bridge_ops = {
+       .attach       = _dba_bridge_attach,
+       .mode_fixup   = _dba_bridge_mode_fixup,
+       .pre_enable   = _dba_bridge_pre_enable,
+       .enable       = _dba_bridge_enable,
+       .disable      = _dba_bridge_disable,
+       .post_disable = _dba_bridge_post_disable,
+       .mode_set     = _dba_bridge_mode_set,
+};
+
+struct drm_bridge *dba_bridge_init(struct drm_device *dev,
+                               struct drm_encoder *encoder,
+                               struct dba_bridge_init *data)
+{
+       int rc = 0;
+       struct dba_bridge *bridge;
+       struct msm_drm_private *priv = NULL;
+
+       if (!dev || !encoder || !data) {
+               SDE_ERROR("dev=%pK or encoder=%pK or data=%pK is NULL\n",
+                               dev, encoder, data);
+               rc = -EINVAL;
+               goto error;
+       }
+
+       priv = dev->dev_private;
+       if (!priv) {
+               SDE_ERROR("Private data is not present\n");
+               rc = -EINVAL;
+               goto error;
+       }
+
+       bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+       if (!bridge) {
+               SDE_ERROR("out of memory\n");
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       INIT_LIST_HEAD(&bridge->list);
+       strlcpy(bridge->client_name, data->client_name,
+                                       MSM_DBA_CLIENT_NAME_LEN);
+       strlcpy(bridge->chip_name, data->chip_name,
+                                       MSM_DBA_CHIP_NAME_MAX_LEN);
+       bridge->id = data->id;
+       bridge->display = data->display;
+       bridge->hdmi_mode = data->hdmi_mode;
+       bridge->num_of_input_lanes = data->num_of_input_lanes;
+       bridge->pluggable = data->pluggable;
+       bridge->panel_count = data->panel_count;
+       bridge->base.funcs = &_dba_bridge_ops;
+       bridge->base.encoder = encoder;
+
+       rc = drm_bridge_attach(dev, &bridge->base);
+       if (rc) {
+               SDE_ERROR("failed to attach bridge, rc=%d\n", rc);
+               goto error_free_bridge;
+       }
+
+       if (data->precede_bridge) {
+               /* Insert current bridge */
+               bridge->base.next = data->precede_bridge->next;
+               data->precede_bridge->next = &bridge->base;
+       } else {
+               encoder->bridge = &bridge->base;
+       }
+
+       if (!bridge->pluggable) {
+               if (bridge->ops.power_on)
+                       bridge->ops.power_on(bridge->dba_ctx, true, 0);
+               if (bridge->ops.check_hpd)
+                       bridge->ops.check_hpd(bridge->dba_ctx, 0);
+       }
+
+       return &bridge->base;
+
+error_free_bridge:
+       kfree(bridge);
+error:
+       return ERR_PTR(rc);
+}
+
+void dba_bridge_cleanup(struct drm_bridge *bridge)
+{
+       struct dba_bridge *d_bridge = to_dba_bridge(bridge);
+
+       if (!bridge)
+               return;
+
+       if (IS_ENABLED(CONFIG_MSM_DBA)) {
+               if (!IS_ERR_OR_NULL(d_bridge->dba_ctx))
+                       msm_dba_deregister_client(d_bridge->dba_ctx);
+       }
+
+       if (d_bridge->base.encoder)
+               d_bridge->base.encoder->bridge = NULL;
+
+       kfree(bridge);
+}
diff --git a/drivers/gpu/drm/msm/dba_bridge.h b/drivers/gpu/drm/msm/dba_bridge.h
new file mode 100644 (file)
index 0000000..5562d2b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DBA_BRIDGE_H_
+#define _DBA_BRIDGE_H_
+
+#include <linux/types.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "msm_drv.h"
+
+/**
+ * struct dba_bridge_init - Init parameters for DBA bridge
+ * @client_name:          Client's name who calls the init
+ * @chip_name:            Bridge chip name
+ * @id:                   Bridge driver index
+ * @display:              Private display handle
+ * @hdmi_mode:            HDMI or DVI mode for the sink
+ * @num_of_input_lanes:   Number of input lanes in case of DSI/LVDS
+ * @precede_bridge:       Precede bridge chip
+ * @pluggable:            If it's pluggable
+ * @panel_count:          Number of panels attached to this display
+ */
+struct dba_bridge_init {
+       const char *client_name;
+       const char *chip_name;
+       u32 id;
+       void *display;
+       bool hdmi_mode;
+       u32 num_of_input_lanes;
+       struct drm_bridge *precede_bridge;
+       bool pluggable;
+       u32 panel_count;
+};
+
+/**
+ * dba_bridge_init - Initialize the DBA bridge
+ * @dev:           Pointer to drm device handle
+ * @encoder:       Pointer to drm encoder handle
+ * @data:          Pointer to init data
+ * Returns: pointer of struct drm_bridge
+ */
+struct drm_bridge *dba_bridge_init(struct drm_device *dev,
+                               struct drm_encoder *encoder,
+                               struct dba_bridge_init *data);
+
+/**
+ * dba_bridge_cleanup - Clean up the DBA bridge
+ * @bridge:           Pointer to DBA bridge handle
+ * Returns: void
+ */
+void dba_bridge_cleanup(struct drm_bridge *bridge);
+
+#endif /* _DBA_BRIDGE_H_ */
index ca04eed..2f0f6c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -85,6 +85,14 @@ void dsi_ctrl_hw_14_host_setup(struct dsi_ctrl_hw *ctrl,
 
        DSI_W32(ctrl, DSI_CTRL, reg_value);
 
+       /* Force clock lane in HS */
+       reg_value = DSI_R32(ctrl, DSI_LANE_CTRL);
+       if (cfg->force_clk_lane_hs)
+               reg_value |= BIT(28);
+       else
+               reg_value &= ~BIT(28);
+       DSI_W32(ctrl, DSI_LANE_CTRL, reg_value);
+
        pr_debug("[DSI_%d]Host configuration complete\n", ctrl->index);
 }
 
@@ -604,8 +612,9 @@ void dsi_ctrl_hw_14_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
 {
        u32 reg = 0;
 
+       reg = DSI_R32(ctrl, DSI_LANE_CTRL);
        if (lanes & DSI_CLOCK_LANE)
-               reg = BIT(4);
+               reg |= BIT(4);
        if (lanes & DSI_DATA_LANE_0)
                reg |= BIT(0);
        if (lanes & DSI_DATA_LANE_1)
@@ -664,7 +673,8 @@ void dsi_ctrl_hw_14_clear_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
        u32 reg = 0;
 
        reg = DSI_R32(ctrl, DSI_LANE_CTRL);
-       reg &= ~BIT(4); /* clock lane */
+       if (lanes & DSI_CLOCK_LANE)
+               reg &= ~BIT(4); /* clock lane */
        if (lanes & DSI_DATA_LANE_0)
                reg &= ~BIT(0);
        if (lanes & DSI_DATA_LANE_1)
@@ -679,7 +689,18 @@ void dsi_ctrl_hw_14_clear_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
         * HPG recommends separate writes for clearing ULPS_REQUEST and
         * ULPS_EXIT.
         */
-       DSI_W32(ctrl, DSI_LANE_CTRL, 0x0);
+       reg = DSI_R32(ctrl, DSI_LANE_CTRL);
+       if (lanes & DSI_CLOCK_LANE)
+               reg &= ~BIT(12);
+       if (lanes & DSI_DATA_LANE_0)
+               reg &= ~BIT(8);
+       if (lanes & DSI_DATA_LANE_1)
+               reg &= ~BIT(9);
+       if (lanes & DSI_DATA_LANE_2)
+               reg &= ~BIT(10);
+       if (lanes & DSI_DATA_LANE_3)
+               reg &= ~BIT(11);
+       DSI_W32(ctrl, DSI_LANE_CTRL, reg);
 
        pr_debug("[DSI_%d] ULPS request cleared\n", ctrl->index);
 }
index 2caa32e..d9fcec6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -259,6 +259,7 @@ struct dsi_lane_mapping {
  * @ignore_rx_eot:       Ignore Rx EOT packets if set to true.
  * @append_tx_eot:       Append EOT packets for forward transmissions if set to
  *                       true.
+ * @force_clk_lane_hs:   Force clock lane in high speed mode.
  */
 struct dsi_host_common_cfg {
        enum dsi_pixel_format dst_format;
@@ -277,6 +278,7 @@ struct dsi_host_common_cfg {
        u32 t_clk_pre;
        bool ignore_rx_eot;
        bool append_tx_eot;
+       bool force_clk_lane_hs;
 };
 
 /**
index 5a166a4..f2412da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
 #include <linux/of.h>
 
 #include "msm_drv.h"
+#include "sde_kms.h"
 #include "dsi_display.h"
 #include "dsi_panel.h"
 #include "dsi_ctrl.h"
 #include "dsi_ctrl_hw.h"
 #include "dsi_drm.h"
+#include "dba_bridge.h"
 
 #define to_dsi_display(x) container_of(x, struct dsi_display, host)
+#define DSI_DBA_CLIENT_NAME "dsi"
 
 static DEFINE_MUTEX(dsi_display_list_lock);
 static LIST_HEAD(dsi_display_list);
@@ -45,7 +48,7 @@ int dsi_display_set_backlight(void *display, u32 bl_lvl)
        if (dsi_display == NULL)
                return -EINVAL;
 
-       panel = dsi_display->panel;
+       panel = dsi_display->panel[0];
 
        rc = dsi_panel_set_backlight(panel, bl_lvl);
        if (rc)
@@ -87,8 +90,9 @@ static ssize_t debugfs_dump_info_read(struct file *file,
                                display->ctrl[i].phy->name);
        }
 
-       len += snprintf(buf + len, (SZ_4K - len),
-                       "\tPanel = %s\n", display->panel->name);
+       for (i = 0; i < display->panel_count; i++)
+               len += snprintf(buf + len, (SZ_4K - len),
+                       "\tPanel_%d = %s\n", i, display->panel[i]->name);
 
        len += snprintf(buf + len, (SZ_4K - len),
                        "\tClock master = %s\n",
@@ -1108,7 +1112,7 @@ static int dsi_display_parse_lane_map(struct dsi_display *display)
 static int dsi_display_parse_dt(struct dsi_display *display)
 {
        int rc = 0;
-       int i;
+       int i, size;
        u32 phy_count = 0;
        struct device_node *of_node;
 
@@ -1151,14 +1155,69 @@ static int dsi_display_parse_dt(struct dsi_display *display)
                goto error;
        }
 
-       of_node = of_parse_phandle(display->pdev->dev.of_node,
-                                  "qcom,dsi-panel", 0);
-       if (!of_node) {
-               pr_err("No Panel device present\n");
+       if (of_get_property(display->pdev->dev.of_node, "qcom,dsi-panel",
+                       &size)) {
+               display->panel_count = size / sizeof(int);
+               display->panel_of = devm_kzalloc(&display->pdev->dev,
+                       sizeof(struct device_node *) * display->panel_count,
+                       GFP_KERNEL);
+               if (!display->panel_of) {
+                       SDE_ERROR("out of memory for panel_of\n");
+                       rc = -ENOMEM;
+                       goto error;
+               }
+               display->panel = devm_kzalloc(&display->pdev->dev,
+                       sizeof(struct dsi_panel *) * display->panel_count,
+                       GFP_KERNEL);
+               if (!display->panel) {
+                       SDE_ERROR("out of memory for panel\n");
+                       rc = -ENOMEM;
+                       goto error;
+               }
+               for (i = 0; i < display->panel_count; i++) {
+                       display->panel_of[i] =
+                               of_parse_phandle(display->pdev->dev.of_node,
+                               "qcom,dsi-panel", i);
+                       if (!display->panel_of[i]) {
+                               SDE_ERROR("of_parse dsi-panel failed\n");
+                               rc = -ENODEV;
+                               goto error;
+                       }
+               }
+       } else {
+               SDE_ERROR("No qcom,dsi-panel of node\n");
                rc = -ENODEV;
                goto error;
-       } else {
-               display->panel_of = of_node;
+       }
+
+       if (of_get_property(display->pdev->dev.of_node, "qcom,bridge-index",
+                       &size)) {
+               if (size / sizeof(int) != display->panel_count) {
+                       SDE_ERROR("size=%lu is different than count=%u\n",
+                               size / sizeof(int), display->panel_count);
+                       rc = -EINVAL;
+                       goto error;
+               }
+               display->bridge_idx = devm_kzalloc(&display->pdev->dev,
+                       sizeof(u32) * display->panel_count, GFP_KERNEL);
+               if (!display->bridge_idx) {
+                       SDE_ERROR("out of memory for bridge_idx\n");
+                       rc = -ENOMEM;
+                       goto error;
+               }
+               for (i = 0; i < display->panel_count; i++) {
+                       rc = of_property_read_u32_index(
+                               display->pdev->dev.of_node,
+                               "qcom,bridge-index", i,
+                               &(display->bridge_idx[i]));
+                       if (rc) {
+                               SDE_ERROR(
+                                       "read bridge-index error,i=%d rc=%d\n",
+                                       i, rc);
+                               rc = -ENODEV;
+                               goto error;
+                       }
+               }
        }
 
        rc = dsi_display_parse_lane_map(display);
@@ -1167,6 +1226,16 @@ static int dsi_display_parse_dt(struct dsi_display *display)
                goto error;
        }
 error:
+       if (rc) {
+               if (display->panel_of)
+                       for (i = 0; i < display->panel_count; i++)
+                               if (display->panel_of[i])
+                                       of_node_put(display->panel_of[i]);
+               devm_kfree(&display->pdev->dev, display->panel_of);
+               devm_kfree(&display->pdev->dev, display->panel);
+               devm_kfree(&display->pdev->dev, display->bridge_idx);
+               display->panel_count = 0;
+       }
        return rc;
 }
 
@@ -1196,12 +1265,15 @@ static int dsi_display_res_init(struct dsi_display *display)
                }
        }
 
-       display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of);
-       if (IS_ERR_OR_NULL(display->panel)) {
-               rc = PTR_ERR(display->panel);
-               pr_err("failed to get panel, rc=%d\n", rc);
-               display->panel = NULL;
-               goto error_ctrl_put;
+       for (i = 0; i < display->panel_count; i++) {
+               display->panel[i] = dsi_panel_get(&display->pdev->dev,
+                                       display->panel_of[i]);
+               if (IS_ERR_OR_NULL(display->panel)) {
+                       rc = PTR_ERR(display->panel);
+                       pr_err("failed to get panel, rc=%d\n", rc);
+                       display->panel[i] = NULL;
+                       goto error_ctrl_put;
+               }
        }
 
        rc = dsi_display_clocks_init(display);
@@ -1230,6 +1302,9 @@ static int dsi_display_res_deinit(struct dsi_display *display)
        if (rc)
                pr_err("clocks deinit failed, rc=%d\n", rc);
 
+       for (i = 0; i < display->panel_count; i++)
+               dsi_panel_put(display->panel[i]);
+
        for (i = 0; i < display->ctrl_count; i++) {
                ctrl = &display->ctrl[i];
                dsi_phy_put(ctrl->phy);
@@ -1279,7 +1354,7 @@ static bool dsi_display_is_seamless_dfps_possible(
                return false;
        }
 
-       cur = &display->panel->mode;
+       cur = &display->panel[0]->mode;
 
        if (cur->timing.h_active != tgt->timing.h_active) {
                pr_debug("timing.h_active differs %d %d\n",
@@ -1388,7 +1463,7 @@ static int dsi_display_dfps_update(struct dsi_display *display,
        }
        timing = &dsi_mode->timing;
 
-       dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
+       dsi_panel_get_dfps_caps(display->panel[0], &dfps_caps);
        if (!dfps_caps.dfps_support) {
                pr_err("dfps not supported\n");
                return -ENOTSUPP;
@@ -1425,7 +1500,7 @@ static int dsi_display_dfps_update(struct dsi_display *display,
                }
        }
 
-       panel_mode = &display->panel->mode;
+       panel_mode = &display->panel[0]->mode;
        memcpy(panel_mode, dsi_mode, sizeof(*panel_mode));
 
 error:
@@ -1493,7 +1568,8 @@ static int dsi_display_get_dfps_timing(struct dsi_display *display,
        }
        m_ctrl = display->ctrl[display->clk_master_idx].ctrl;
 
-       dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
+       /* Only check the first panel */
+       dsi_panel_get_dfps_caps(display->panel[0], &dfps_caps);
        if (!dfps_caps.dfps_support) {
                pr_err("dfps not supported by panel\n");
                return -EINVAL;
@@ -1574,7 +1650,7 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
        int i;
        struct dsi_display_ctrl *ctrl;
 
-       rc = dsi_panel_get_host_cfg_for_mode(display->panel,
+       rc = dsi_panel_get_host_cfg_for_mode(display->panel[0],
                                             mode,
                                             &display->config);
        if (rc) {
@@ -1687,7 +1763,7 @@ static int dsi_display_bind(struct device *dev,
        struct drm_device *drm;
        struct dsi_display *display;
        struct platform_device *pdev = to_platform_device(dev);
-       int i, rc = 0;
+       int i, j, rc = 0;
 
        if (!dev || !pdev || !master) {
                pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
@@ -1737,15 +1813,19 @@ static int dsi_display_bind(struct device *dev,
                goto error_ctrl_deinit;
        }
 
-       rc = dsi_panel_drv_init(display->panel, &display->host);
-       if (rc) {
-               if (rc != -EPROBE_DEFER)
-                       pr_err("[%s] failed to initialize panel driver, rc=%d\n",
-                              display->name, rc);
-               goto error_host_deinit;
+       for (j = 0; j < display->panel_count; j++) {
+               rc = dsi_panel_drv_init(display->panel[j], &display->host);
+               if (rc) {
+                       if (rc != -EPROBE_DEFER)
+                               SDE_ERROR(
+                               "[%s]Failed to init panel driver, rc=%d\n",
+                               display->name, rc);
+                       goto error_panel_deinit;
+               }
        }
 
-       rc = dsi_panel_get_mode_count(display->panel, &display->num_of_modes);
+       rc = dsi_panel_get_mode_count(display->panel[0],
+                                       &display->num_of_modes);
        if (rc) {
                pr_err("[%s] failed to get mode count, rc=%d\n",
                       display->name, rc);
@@ -1756,8 +1836,8 @@ static int dsi_display_bind(struct device *dev,
        goto error;
 
 error_panel_deinit:
-       (void)dsi_panel_drv_deinit(display->panel);
-error_host_deinit:
+       for (j--; j >= 0; j--)
+               (void)dsi_panel_drv_deinit(display->panel[j]);
        (void)dsi_display_mipi_host_deinit(display);
 error_ctrl_deinit:
        for (i = i - 1; i >= 0; i--) {
@@ -1798,10 +1878,12 @@ static void dsi_display_unbind(struct device *dev,
 
        mutex_lock(&display->display_lock);
 
-       rc = dsi_panel_drv_deinit(display->panel);
-       if (rc)
-               pr_err("[%s] failed to deinit panel driver, rc=%d\n",
-                      display->name, rc);
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_drv_deinit(display->panel[i]);
+               if (rc)
+                       SDE_ERROR("[%s] failed to deinit panel driver, rc=%d\n",
+                                       display->name, rc);
+       }
 
        rc = dsi_display_mipi_host_deinit(display);
        if (rc)
@@ -1870,7 +1952,7 @@ int dsi_display_dev_probe(struct platform_device *pdev)
        display->pdev = pdev;
        platform_set_drvdata(pdev, display);
        mutex_lock(&dsi_display_list_lock);
-       list_add(&display->list, &dsi_display_list);
+       list_add_tail(&display->list, &dsi_display_list);
        mutex_unlock(&dsi_display_list_lock);
 
        if (display->is_active) {
@@ -1890,7 +1972,7 @@ int dsi_display_dev_probe(struct platform_device *pdev)
 
 int dsi_display_dev_remove(struct platform_device *pdev)
 {
-       int rc = 0;
+       int rc = 0, i;
        struct dsi_display *display;
        struct dsi_display *pos, *tmp;
 
@@ -1913,6 +1995,13 @@ int dsi_display_dev_remove(struct platform_device *pdev)
        mutex_unlock(&dsi_display_list_lock);
 
        platform_set_drvdata(pdev, NULL);
+       if (display->panel_of)
+               for (i = 0; i < display->panel_count; i++)
+                       if (display->panel_of[i])
+                               of_node_put(display->panel_of[i]);
+       devm_kfree(&pdev->dev, display->panel_of);
+       devm_kfree(&pdev->dev, display->panel);
+       devm_kfree(&pdev->dev, display->bridge_idx);
        devm_kfree(&pdev->dev, display);
        return rc;
 }
@@ -1984,9 +2073,15 @@ void dsi_display_set_active_state(struct dsi_display *display, bool is_active)
 int dsi_display_drm_bridge_init(struct dsi_display *display,
                struct drm_encoder *enc)
 {
-       int rc = 0;
+       int rc = 0, i;
        struct dsi_bridge *bridge;
+       struct drm_bridge *dba_bridge;
+       struct dba_bridge_init init_data;
+       struct drm_bridge *precede_bridge;
        struct msm_drm_private *priv = NULL;
+       struct dsi_panel *panel;
+       u32 *bridge_idx;
+       u32 num_of_lanes = 0;
 
        if (!display || !display->drm_dev || !enc) {
                pr_err("invalid param(s)\n");
@@ -1997,44 +2092,112 @@ int dsi_display_drm_bridge_init(struct dsi_display *display,
        priv = display->drm_dev->dev_private;
 
        if (!priv) {
-               pr_err("Private data is not present\n");
+               SDE_ERROR("Private data is not present\n");
                rc = -EINVAL;
-               goto error;
+               goto out;
        }
 
        if (display->bridge) {
-               pr_err("display is already initialize\n");
-               goto error;
+               SDE_ERROR("display is already initialize\n");
+               goto out;
        }
 
        bridge = dsi_drm_bridge_init(display, display->drm_dev, enc);
        if (IS_ERR_OR_NULL(bridge)) {
                rc = PTR_ERR(bridge);
-               pr_err("[%s] brige init failed, %d\n", display->name, rc);
-               goto error;
+               SDE_ERROR("[%s] brige init failed, %d\n", display->name, rc);
+               goto out;
        }
 
        display->bridge = bridge;
        priv->bridges[priv->num_bridges++] = &bridge->base;
+       precede_bridge = &bridge->base;
+
+       if (display->panel_count >= MAX_BRIDGES - 1) {
+               SDE_ERROR("too many bridge chips=%d\n", display->panel_count);
+               goto error_bridge;
+       }
+
+       for (i = 0; i < display->panel_count; i++) {
+               panel = display->panel[i];
+               if (panel && display->bridge_idx &&
+                       panel->dba_config.dba_panel) {
+                       bridge_idx = display->bridge_idx + i;
+                       num_of_lanes = 0;
+                       memset(&init_data, 0x00, sizeof(init_data));
+                       if (panel->host_config.data_lanes & DSI_DATA_LANE_0)
+                               num_of_lanes++;
+                       if (panel->host_config.data_lanes & DSI_DATA_LANE_1)
+                               num_of_lanes++;
+                       if (panel->host_config.data_lanes & DSI_DATA_LANE_2)
+                               num_of_lanes++;
+                       if (panel->host_config.data_lanes & DSI_DATA_LANE_3)
+                               num_of_lanes++;
+                       init_data.client_name = DSI_DBA_CLIENT_NAME;
+                       init_data.chip_name = panel->dba_config.bridge_name;
+                       init_data.id = *bridge_idx;
+                       init_data.display = display;
+                       init_data.hdmi_mode = panel->dba_config.hdmi_mode;
+                       init_data.num_of_input_lanes = num_of_lanes;
+                       init_data.precede_bridge = precede_bridge;
+                       init_data.panel_count = display->panel_count;
+                       dba_bridge = dba_bridge_init(display->drm_dev, enc,
+                                                       &init_data);
+                       if (IS_ERR_OR_NULL(dba_bridge)) {
+                               rc = PTR_ERR(dba_bridge);
+                               SDE_ERROR("[%s:%d] dba brige init failed, %d\n",
+                                       init_data.chip_name, init_data.id, rc);
+                               goto error_dba_bridge;
+                       }
+                       priv->bridges[priv->num_bridges++] = dba_bridge;
+                       precede_bridge = dba_bridge;
+               }
+       }
 
-error:
+       goto out;
+
+error_dba_bridge:
+       for (i = 1; i < MAX_BRIDGES; i++) {
+               dba_bridge_cleanup(priv->bridges[i]);
+               priv->bridges[i] = NULL;
+       }
+error_bridge:
+       dsi_drm_bridge_cleanup(display->bridge);
+       display->bridge = NULL;
+       priv->bridges[0] = NULL;
+       priv->num_bridges = 0;
+out:
        mutex_unlock(&display->display_lock);
        return rc;
 }
 
 int dsi_display_drm_bridge_deinit(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i;
+       struct msm_drm_private *priv = NULL;
 
        if (!display) {
-               pr_err("Invalid params\n");
+               SDE_ERROR("Invalid params\n");
+               return -EINVAL;
+       }
+       priv = display->drm_dev->dev_private;
+
+       if (!priv) {
+               SDE_ERROR("Private data is not present\n");
                return -EINVAL;
        }
 
        mutex_lock(&display->display_lock);
 
+       for (i = 1; i < MAX_BRIDGES; i++) {
+               dba_bridge_cleanup(priv->bridges[i]);
+               priv->bridges[i] = NULL;
+       }
+
        dsi_drm_bridge_cleanup(display->bridge);
        display->bridge = NULL;
+       priv->bridges[0] = NULL;
+       priv->num_bridges = 0;
 
        mutex_unlock(&display->display_lock);
        return rc;
@@ -2053,7 +2216,7 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
        display = disp;
 
        mutex_lock(&display->display_lock);
-       rc = dsi_panel_get_phy_props(display->panel, &phy_props);
+       rc = dsi_panel_get_phy_props(display->panel[0], &phy_props);
        if (rc) {
                pr_err("[%s] failed to get panel phy props, rc=%d\n",
                       display->name, rc);
@@ -2073,7 +2236,7 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
        info->max_height = 1080;
        info->compression = MSM_DISPLAY_COMPRESS_NONE;
 
-       switch (display->panel->mode.panel_mode) {
+       switch (display->panel[0]->mode.panel_mode) {
        case DSI_OP_VIDEO_MODE:
                info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
                break;
@@ -2082,7 +2245,7 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
                break;
        default:
                pr_err("unknwown dsi panel mode %d\n",
-                               display->panel->mode.panel_mode);
+                               display->panel[0]->mode.panel_mode);
                break;
        }
 error:
@@ -2106,7 +2269,7 @@ int dsi_display_get_modes(struct dsi_display *display,
 
        mutex_lock(&display->display_lock);
 
-       rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
+       rc = dsi_panel_get_dfps_caps(display->panel[0], &dfps_caps);
        if (rc) {
                pr_err("[%s] failed to get dfps caps from panel\n",
                                display->name);
@@ -2127,7 +2290,8 @@ int dsi_display_get_modes(struct dsi_display *display,
                /* Insert the dfps "sub-modes" between main panel modes */
                int panel_mode_idx = i / num_dfps_rates;
 
-               rc = dsi_panel_get_mode(display->panel, panel_mode_idx, modes);
+               rc = dsi_panel_get_mode(display->panel[0], panel_mode_idx,
+                                       modes);
                if (rc) {
                        pr_err("[%s] failed to get mode from panel\n",
                               display->name);
@@ -2178,7 +2342,7 @@ int dsi_display_validate_mode(struct dsi_display *display,
        adj_mode = *mode;
        adjust_timing_by_ctrl_count(display, &adj_mode);
 
-       rc = dsi_panel_validate_mode(display->panel, &adj_mode);
+       rc = dsi_panel_validate_mode(display->panel[0], &adj_mode);
        if (rc) {
                pr_err("[%s] panel mode validation failed, rc=%d\n",
                       display->name, rc);
@@ -2278,7 +2442,7 @@ error:
 
 int dsi_display_prepare(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i, j;
 
        if (!display) {
                pr_err("Invalid params\n");
@@ -2287,11 +2451,13 @@ int dsi_display_prepare(struct dsi_display *display)
 
        mutex_lock(&display->display_lock);
 
-       rc = dsi_panel_pre_prepare(display->panel);
-       if (rc) {
-               pr_err("[%s] panel pre-prepare failed, rc=%d\n",
-                      display->name, rc);
-               goto error;
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_pre_prepare(display->panel[i]);
+               if (rc) {
+                       SDE_ERROR("[%s] panel pre-prepare failed, rc=%d\n",
+                                       display->name, rc);
+                       goto error_panel_post_unprep;
+               }
        }
 
        rc = dsi_display_ctrl_power_on(display);
@@ -2349,15 +2515,20 @@ int dsi_display_prepare(struct dsi_display *display)
                goto error_ctrl_link_off;
        }
 
-       rc = dsi_panel_prepare(display->panel);
-       if (rc) {
-               pr_err("[%s] panel prepare failed, rc=%d\n", display->name, rc);
-               goto error_host_engine_off;
+       for (j = 0; j < display->panel_count; j++) {
+               rc = dsi_panel_prepare(display->panel[j]);
+               if (rc) {
+                       SDE_ERROR("[%s] panel prepare failed, rc=%d\n",
+                                       display->name, rc);
+                       goto error_panel_unprep;
+               }
        }
 
        goto error;
 
-error_host_engine_off:
+error_panel_unprep:
+       for (j--; j >= 0; j--)
+               (void)dsi_panel_unprepare(display->panel[j]);
        (void)dsi_display_ctrl_host_disable(display);
 error_ctrl_link_off:
        (void)dsi_display_ctrl_link_clk_off(display);
@@ -2372,7 +2543,8 @@ error_phy_pwr_off:
 error_ctrl_pwr_off:
        (void)dsi_display_ctrl_power_off(display);
 error_panel_post_unprep:
-       (void)dsi_panel_post_unprepare(display->panel);
+       for (i--; i >= 0; i--)
+               (void)dsi_panel_post_unprepare(display->panel[i]);
 error:
        mutex_unlock(&display->display_lock);
        return rc;
@@ -2380,7 +2552,7 @@ error:
 
 int dsi_display_enable(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i;
 
        if (!display) {
                pr_err("Invalid params\n");
@@ -2389,11 +2561,13 @@ int dsi_display_enable(struct dsi_display *display)
 
        mutex_lock(&display->display_lock);
 
-       rc = dsi_panel_enable(display->panel);
-       if (rc) {
-               pr_err("[%s] failed to enable DSI panel, rc=%d\n",
-                      display->name, rc);
-               goto error;
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_enable(display->panel[i]);
+               if (rc) {
+                       SDE_ERROR("[%s] failed to enable DSI panel, rc=%d\n",
+                                       display->name, rc);
+                       goto error_disable_panel;
+               }
        }
 
        if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
@@ -2419,7 +2593,8 @@ int dsi_display_enable(struct dsi_display *display)
        goto error;
 
 error_disable_panel:
-       (void)dsi_panel_disable(display->panel);
+       for (i--; i >= 0; i--)
+               (void)dsi_panel_disable(display->panel[i]);
 error:
        mutex_unlock(&display->display_lock);
        return rc;
@@ -2427,7 +2602,7 @@ error:
 
 int dsi_display_post_enable(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i;
 
        if (!display) {
                pr_err("Invalid params\n");
@@ -2436,10 +2611,12 @@ int dsi_display_post_enable(struct dsi_display *display)
 
        mutex_lock(&display->display_lock);
 
-       rc = dsi_panel_post_enable(display->panel);
-       if (rc)
-               pr_err("[%s] panel post-enable failed, rc=%d\n",
-                      display->name, rc);
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_post_enable(display->panel[i]);
+               if (rc)
+                       SDE_ERROR("[%s] panel post-enable failed, rc=%d\n",
+                                       display->name, rc);
+       }
 
        mutex_unlock(&display->display_lock);
        return rc;
@@ -2447,7 +2624,7 @@ int dsi_display_post_enable(struct dsi_display *display)
 
 int dsi_display_pre_disable(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i;
 
        if (!display) {
                pr_err("Invalid params\n");
@@ -2456,10 +2633,12 @@ int dsi_display_pre_disable(struct dsi_display *display)
 
        mutex_lock(&display->display_lock);
 
-       rc = dsi_panel_pre_disable(display->panel);
-       if (rc)
-               pr_err("[%s] panel pre-disable failed, rc=%d\n",
-                      display->name, rc);
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_pre_disable(display->panel[i]);
+               if (rc)
+                       SDE_ERROR("[%s] panel pre-disable failed, rc=%d\n",
+                                       display->name, rc);
+       }
 
        mutex_unlock(&display->display_lock);
        return rc;
@@ -2467,7 +2646,7 @@ int dsi_display_pre_disable(struct dsi_display *display)
 
 int dsi_display_disable(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i;
 
        if (!display) {
                pr_err("Invalid params\n");
@@ -2481,10 +2660,12 @@ int dsi_display_disable(struct dsi_display *display)
                pr_err("[%s] display wake up failed, rc=%d\n",
                       display->name, rc);
 
-       rc = dsi_panel_disable(display->panel);
-       if (rc)
-               pr_err("[%s] failed to disable DSI panel, rc=%d\n",
-                      display->name, rc);
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_disable(display->panel[i]);
+               if (rc)
+                       SDE_ERROR("[%s] failed to disable DSI panel, rc=%d\n",
+                                       display->name, rc);
+       }
 
        if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
                rc = dsi_display_vid_engine_disable(display);
@@ -2507,7 +2688,7 @@ int dsi_display_disable(struct dsi_display *display)
 
 int dsi_display_unprepare(struct dsi_display *display)
 {
-       int rc = 0;
+       int rc = 0, i;
 
        if (!display) {
                pr_err("Invalid params\n");
@@ -2521,10 +2702,12 @@ int dsi_display_unprepare(struct dsi_display *display)
                pr_err("[%s] display wake up failed, rc=%d\n",
                       display->name, rc);
 
-       rc = dsi_panel_unprepare(display->panel);
-       if (rc)
-               pr_err("[%s] panel unprepare failed, rc=%d\n",
-                      display->name, rc);
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_unprepare(display->panel[i]);
+               if (rc)
+                       SDE_ERROR("[%s] panel unprepare failed, rc=%d\n",
+                                       display->name, rc);
+       }
 
        rc = dsi_display_ctrl_host_disable(display);
        if (rc)
@@ -2561,10 +2744,12 @@ int dsi_display_unprepare(struct dsi_display *display)
                pr_err("[%s] failed to power DSI vregs, rc=%d\n",
                       display->name, rc);
 
-       rc = dsi_panel_post_unprepare(display->panel);
-       if (rc)
-               pr_err("[%s] panel post-unprepare failed, rc=%d\n",
-                      display->name, rc);
+       for (i = 0; i < display->panel_count; i++) {
+               rc = dsi_panel_post_unprepare(display->panel[i]);
+               if (rc)
+                       pr_err("[%s] panel post-unprepare failed, rc=%d\n",
+                               display->name, rc);
+       }
 
        mutex_unlock(&display->display_lock);
        return rc;
index b77bf26..210b8d0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -102,8 +102,11 @@ struct dsi_display_clk_info {
  * @display_lock:     Mutex for dsi_display interface.
  * @ctrl_count:       Number of DSI interfaces required by panel.
  * @ctrl:             Controller information for DSI display.
+ * @panel_count:      Number of DSI panel.
  * @panel:            Handle to DSI panel.
- * @panel_of:         pHandle to DSI panel.
+ * @panel_of:         pHandle to DSI panel, it's an array with panel_count
+ *                   of struct device_node pointers.
+ * @bridge_idx:       Bridge chip index for each panel_of.
  * @type:             DSI display type.
  * @clk_master_idx:   The master controller for controlling clocks. This is an
  *                   index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
@@ -133,8 +136,10 @@ struct dsi_display {
        struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY];
 
        /* panel info */
-       struct dsi_panel *panel;
-       struct device_node *panel_of;
+       u32 panel_count;
+       struct dsi_panel **panel;
+       struct device_node **panel_of;
+       u32 *bridge_idx;
 
        enum dsi_display_type type;
        u32 clk_master_idx;
index a1adecf..995cda9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -213,18 +213,21 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
                                struct drm_display_mode *adjusted_mode)
 {
        struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
+       struct dsi_panel *panel;
 
-       if (!bridge || !mode || !adjusted_mode) {
+       if (!bridge || !mode || !adjusted_mode || !c_bridge->display ||
+               !c_bridge->display->panel[0]) {
                pr_err("Invalid params\n");
                return;
        }
 
+       /* dsi drm bridge is always the first panel */
+       panel = c_bridge->display->panel[0];
        memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
        convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
 
        pr_debug("note: using panel cmd/vid mode instead of user val\n");
-       c_bridge->dsi_mode.panel_mode =
-               c_bridge->display->panel->mode.panel_mode;
+       c_bridge->dsi_mode.panel_mode = panel->mode.panel_mode;
 }
 
 static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
@@ -271,6 +274,7 @@ int dsi_conn_post_init(struct drm_connector *connector,
 {
        struct dsi_display *dsi_display = display;
        struct dsi_panel *panel;
+       int i;
 
        if (!info || !dsi_display)
                return -EINVAL;
@@ -299,60 +303,65 @@ int dsi_conn_post_init(struct drm_connector *connector,
                break;
        }
 
-       if (!dsi_display->panel) {
-               pr_debug("invalid panel data\n");
-               goto end;
-       }
-
-       panel = dsi_display->panel;
-       sde_kms_info_add_keystr(info, "panel name", panel->name);
-
-       switch (panel->mode.panel_mode) {
-       case DSI_OP_VIDEO_MODE:
-               sde_kms_info_add_keystr(info, "panel mode", "video");
-               break;
-       case DSI_OP_CMD_MODE:
-               sde_kms_info_add_keystr(info, "panel mode", "command");
-               sde_kms_info_add_keyint(info, "mdp_transfer_time_us",
-                               panel->cmd_config.mdp_transfer_time_us);
-               break;
-       default:
-               pr_debug("invalid panel type:%d\n", panel->mode.panel_mode);
-               break;
-       }
-       sde_kms_info_add_keystr(info, "dfps support",
-                       panel->dfps_caps.dfps_support ? "true" : "false");
+       for (i = 0; i < dsi_display->panel_count; i++) {
+               if (!dsi_display->panel[i]) {
+                       pr_debug("invalid panel data\n");
+                       goto end;
+               }
 
-       switch (panel->phy_props.rotation) {
-       case DSI_PANEL_ROTATE_NONE:
-               sde_kms_info_add_keystr(info, "panel orientation", "none");
-               break;
-       case DSI_PANEL_ROTATE_H_FLIP:
-               sde_kms_info_add_keystr(info, "panel orientation", "horz flip");
-               break;
-       case DSI_PANEL_ROTATE_V_FLIP:
-               sde_kms_info_add_keystr(info, "panel orientation", "vert flip");
-               break;
-       default:
-               pr_debug("invalid panel rotation:%d\n",
+               panel = dsi_display->panel[i];
+               sde_kms_info_add_keystr(info, "panel name", panel->name);
+
+               switch (panel->mode.panel_mode) {
+               case DSI_OP_VIDEO_MODE:
+                       sde_kms_info_add_keystr(info, "panel mode", "video");
+                       break;
+               case DSI_OP_CMD_MODE:
+                       sde_kms_info_add_keystr(info, "panel mode", "command");
+                       break;
+               default:
+                       pr_debug("invalid panel type:%d\n",
+                                       panel->mode.panel_mode);
+                       break;
+               }
+               sde_kms_info_add_keystr(info, "dfps support",
+                               panel->dfps_caps.dfps_support ?
+                                       "true" : "false");
+
+               switch (panel->phy_props.rotation) {
+               case DSI_PANEL_ROTATE_NONE:
+                       sde_kms_info_add_keystr(info, "panel orientation",
+                                               "none");
+                       break;
+               case DSI_PANEL_ROTATE_H_FLIP:
+                       sde_kms_info_add_keystr(info, "panel orientation",
+                                               "horz flip");
+                       break;
+               case DSI_PANEL_ROTATE_V_FLIP:
+                       sde_kms_info_add_keystr(info, "panel orientation",
+                                               "vert flip");
+                       break;
+               default:
+                       pr_debug("invalid panel rotation:%d\n",
                                                panel->phy_props.rotation);
-               break;
-       }
+                       break;
+               }
 
-       switch (panel->bl_config.type) {
-       case DSI_BACKLIGHT_PWM:
-               sde_kms_info_add_keystr(info, "backlight type", "pwm");
-               break;
-       case DSI_BACKLIGHT_WLED:
-               sde_kms_info_add_keystr(info, "backlight type", "wled");
-               break;
-       case DSI_BACKLIGHT_DCS:
-               sde_kms_info_add_keystr(info, "backlight type", "dcs");
-               break;
-       default:
-               pr_debug("invalid panel backlight type:%d\n",
-                                               panel->bl_config.type);
-               break;
+               switch (panel->bl_config.type) {
+               case DSI_BACKLIGHT_PWM:
+                       sde_kms_info_add_keystr(info, "backlight type", "pwm");
+                       break;
+               case DSI_BACKLIGHT_WLED:
+                       sde_kms_info_add_keystr(info, "backlight type", "wled");
+                       break;
+               case DSI_BACKLIGHT_DCS:
+                       sde_kms_info_add_keystr(info, "backlight type", "dcs");
+                       break;
+               default:
+                       pr_debug("invalid panel backlight type:%d\n",
+                                                       panel->bl_config.type);
+                       break;
+               }
        }
 
 end:
index a7a39e6..b1319a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 
+#include "sde_kms.h"
 #include "dsi_panel.h"
 #include "dsi_ctrl_hw.h"
 
@@ -171,10 +172,12 @@ static int dsi_panel_set_pinctrl_state(struct dsi_panel *panel, bool enable)
        else
                state = panel->pinctrl.suspend;
 
-       rc = pinctrl_select_state(panel->pinctrl.pinctrl, state);
-       if (rc)
-               pr_err("[%s] failed to set pin state, rc=%d\n", panel->name,
-                      rc);
+       if (panel->pinctrl.pinctrl && state) {
+               rc = pinctrl_select_state(panel->pinctrl.pinctrl, state);
+               if (rc)
+                       pr_err("[%s] failed to set pin state, rc=%d\n",
+                               panel->name, rc);
+       }
 
        return rc;
 }
@@ -386,6 +389,9 @@ static int dsi_panel_bl_register(struct dsi_panel *panel)
        case DSI_BACKLIGHT_WLED:
                rc = dsi_panel_led_bl_register(panel, bl);
                break;
+       case DSI_BACKLIGHT_UNKNOWN:
+               DRM_INFO("backlight type is unknown\n");
+               break;
        default:
                pr_err("Backlight type(%d) not supported\n", bl->type);
                rc = -ENOTSUPP;
@@ -704,6 +710,8 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host,
        host->append_tx_eot = of_property_read_bool(of_node,
                                                "qcom,mdss-dsi-tx-eot-append");
 
+       host->force_clk_lane_hs = of_property_read_bool(of_node,
+                                       "qcom,mdss-dsi-force-clock-lane-hs");
        return 0;
 }
 
@@ -1348,6 +1356,8 @@ static int dsi_panel_parse_gpios(struct dsi_panel *panel,
 {
        int rc = 0;
 
+       /* Need to set GPIO default value to -1, since 0 is a valid value */
+       panel->reset_config.disp_en_gpio = -1;
        panel->reset_config.reset_gpio = of_get_named_gpio(of_node,
                                              "qcom,platform-reset-gpio",
                                              0);
@@ -1496,6 +1506,33 @@ error:
        return rc;
 }
 
+static int dsi_panel_parse_dba_config(struct dsi_panel *panel,
+                                       struct device_node *of_node)
+{
+       int rc = 0, len = 0;
+
+       panel->dba_config.dba_panel = of_property_read_bool(of_node,
+               "qcom,dba-panel");
+
+       if (panel->dba_config.dba_panel) {
+               panel->dba_config.hdmi_mode = of_property_read_bool(of_node,
+                       "qcom,hdmi-mode");
+
+               panel->dba_config.bridge_name = of_get_property(of_node,
+                       "qcom,bridge-name", &len);
+               if (!panel->dba_config.bridge_name || len <= 0) {
+                       SDE_ERROR(
+                       "%s:%d Unable to read bridge_name, data=%pK,len=%d\n",
+                       __func__, __LINE__, panel->dba_config.bridge_name, len);
+                       rc = -EINVAL;
+                       goto error;
+               }
+       }
+
+error:
+       return rc;
+}
+
 struct dsi_panel *dsi_panel_get(struct device *parent,
                                struct device_node *of_node)
 {
@@ -1560,6 +1597,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
        if (rc)
                pr_err("failed to parse backlight config, rc=%d\n", rc);
 
+       rc = dsi_panel_parse_dba_config(panel, of_node);
+       if (rc)
+               pr_err("failed to parse dba config, rc=%d\n", rc);
+
        panel->panel_of_node = of_node;
        drm_panel_init(&panel->drm_panel);
        mutex_init(&panel->panel_lock);
@@ -1574,6 +1615,9 @@ void dsi_panel_put(struct dsi_panel *panel)
 {
        u32 i;
 
+       if (!panel)
+               return;
+
        for (i = 0; i < DSI_CMD_SET_MAX; i++)
                dsi_panel_destroy_cmd_packets(&panel->cmd_sets[i]);
 
@@ -1614,10 +1658,8 @@ int dsi_panel_drv_init(struct dsi_panel *panel,
        }
 
        rc = dsi_panel_pinctrl_init(panel);
-       if (rc) {
+       if (rc)
                pr_err("[%s] failed to init pinctrl, rc=%d\n", panel->name, rc);
-               goto error_vreg_put;
-       }
 
        rc = dsi_panel_gpio_request(panel);
        if (rc) {
@@ -1640,7 +1682,6 @@ error_gpio_release:
        (void)dsi_panel_gpio_release(panel);
 error_pinctrl_deinit:
        (void)dsi_panel_pinctrl_deinit(panel);
-error_vreg_put:
        (void)dsi_panel_vreg_put(panel);
 exit:
        mutex_unlock(&panel->panel_lock);
index 4d21a4c..8106ed1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -132,6 +132,18 @@ struct dsi_panel_reset_config {
        int disp_en_gpio;
 };
 
+/**
+ * struct dsi_panel_dba - DSI DBA panel information
+ * @dba_panel:          Indicate if it's DBA panel
+ * @bridge_name:        Bridge chip name
+ * @hdmi_mode:          If bridge chip is in hdmi mode.
+ */
+struct dsi_panel_dba {
+       bool dba_panel;
+       const char *bridge_name;
+       bool hdmi_mode;
+};
+
 struct dsi_panel {
        const char *name;
        struct device_node *panel_of_node;
@@ -158,6 +170,8 @@ struct dsi_panel {
        struct dsi_panel_reset_config reset_config;
        struct dsi_pinctrl_info pinctrl;
 
+       struct dsi_panel_dba dba_config;
+
        bool lp11_init;
 };
 
index 6a6d02c..1ff3ee2 100644 (file)
@@ -401,12 +401,111 @@ static const struct file_operations edid_vendor_name_fops = {
        .read = _sde_hdmi_edid_vendor_name_read,
 };
 
+static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in)
+{
+       u32 pclk_delta, pclk;
+       u64 pclk_clip = pclk_in;
+
+       /* as per standard, 0.5% of deviation is allowed */
+       pclk = mode->clock * HDMI_KHZ_TO_HZ;
+       pclk_delta = pclk * 5 / 1000;
+
+       if (pclk_in < (pclk - pclk_delta))
+               pclk_clip = pclk - pclk_delta;
+       else if (pclk_in > (pclk + pclk_delta))
+               pclk_clip = pclk + pclk_delta;
+
+       if (pclk_in != pclk_clip)
+               pr_warn("clip pclk from %lld to %lld\n", pclk_in, pclk_clip);
+
+       return pclk_clip;
+}
+
+/**
+ * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm
+ *
+ * @ppm: ppm is parts per million multiplied by 1000.
+ * return: 0 on success, non-zero in case of failure.
+ *
+ * The input ppm will be clipped if it's more than or less than 5% of the TMDS
+ * clock rate defined by HDMI spec.
+ */
+static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm)
+{
+       struct hdmi *hdmi = display->ctrl.ctrl;
+       struct drm_display_mode *current_mode = &display->mode;
+       u64 cur_pclk, dst_pclk;
+       u64 clip_pclk;
+       int rc = 0;
+
+       if (!hdmi->power_on || !display->connected) {
+               SDE_ERROR("HDMI display is not ready\n");
+               return -EINVAL;
+       }
+
+       /* get current pclk */
+       cur_pclk = hdmi->pixclock;
+       /* get desired pclk */
+       dst_pclk = cur_pclk * (1000000000 + ppm);
+       do_div(dst_pclk, 1000000000);
+
+       clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk);
+
+       /* update pclk */
+       if (clip_pclk != cur_pclk) {
+               SDE_DEBUG("PCLK changes from %llu to %llu when delta is %d\n",
+                               cur_pclk, clip_pclk, ppm);
+
+               rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk);
+               if (rc < 0) {
+                       SDE_ERROR("PLL update failed, reset clock rate\n");
+                       return rc;
+               }
+
+               hdmi->pixclock = clip_pclk;
+       }
+
+       return rc;
+}
+
+static ssize_t _sde_hdmi_debugfs_pll_delta_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 ppm = 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, &ppm))
+               return -EFAULT;
+
+       if (ppm)
+               _sde_hdmi_update_pll_delta(display, ppm);
+
+       return count;
+}
+
+static const struct file_operations pll_delta_fops = {
+       .open = simple_open,
+       .write = _sde_hdmi_debugfs_pll_delta_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;
+       struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file;
 
        dir = debugfs_create_dir(display->name, NULL);
        if (!dir) {
@@ -423,7 +522,19 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
                                        &dump_info_fops);
        if (IS_ERR_OR_NULL(dump_file)) {
                rc = PTR_ERR(dump_file);
-               SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+               SDE_ERROR("[%s]debugfs create dump_info file failed, rc=%d\n",
+                      display->name, rc);
+               goto error_remove_dir;
+       }
+
+       pll_file = debugfs_create_file("pll_delta",
+                                       0644,
+                                       dir,
+                                       display,
+                                       &pll_delta_fops);
+       if (IS_ERR_OR_NULL(pll_file)) {
+               rc = PTR_ERR(pll_file);
+               SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n",
                       display->name, rc);
                goto error_remove_dir;
        }
@@ -1324,6 +1435,28 @@ int sde_hdmi_get_info(struct msm_display_info *info,
        return rc;
 }
 
+int sde_hdmi_set_property(struct drm_connector *connector,
+                       struct drm_connector_state *state,
+                       int property_index,
+                       uint64_t value,
+                       void *display)
+{
+       int rc = 0;
+
+       if (!connector || !display) {
+               SDE_ERROR("connector=%pK or display=%pK is NULL\n",
+                       connector, display);
+               return 0;
+       }
+
+       SDE_DEBUG("\n");
+
+       if (property_index == CONNECTOR_PROP_PLL_DELTA)
+               rc = _sde_hdmi_update_pll_delta(display, value);
+
+       return rc;
+}
+
 u32 sde_hdmi_get_num_of_displays(void)
 {
        u32 count = 0;
index bb3061a..ecdace1 100644 (file)
@@ -80,6 +80,7 @@ struct sde_hdmi_ctrl {
  * @non_pluggable:    If HDMI display is non pluggable
  * @num_of_modes:     Number of modes supported by display if non pluggable.
  * @mode_list:        Mode list if non pluggable.
+ * @mode:             Current display mode.
  * @connected:        If HDMI display is connected.
  * @is_tpg_enabled:   TPG state.
  * @hpd_work:         HPD work structure.
@@ -103,6 +104,7 @@ struct sde_hdmi {
        bool non_pluggable;
        u32 num_of_modes;
        struct list_head mode_list;
+       struct drm_display_mode mode;
        bool connected;
        bool is_tpg_enabled;
 
@@ -270,6 +272,22 @@ int sde_hdmi_get_info(struct msm_display_info *info,
                                void *display);
 
 /**
+ * sde_hdmi_set_property() - set 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_set_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.
  *
@@ -453,5 +471,15 @@ static inline int sde_hdmi_get_info(struct msm_display_info *info,
 {
        return 0;
 }
+
+static inline int sde_hdmi_set_property(struct drm_connector *connector,
+                       struct drm_connector_state *state,
+                       int property_index,
+                       uint64_t value,
+                       void *display)
+{
+       return 0;
+}
+
 #endif /*#else of CONFIG_DRM_SDE_HDMI*/
 #endif /* _SDE_HDMI_H_ */
index 13ea49c..48a3a93 100644 (file)
@@ -30,8 +30,6 @@
 #define HDMI_AUDIO_INFO_FRAME_PACKET_VERSION 0x1
 #define HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH 0x0A
 
-#define HDMI_KHZ_TO_HZ 1000
-#define HDMI_MHZ_TO_HZ 1000000
 #define HDMI_ACR_N_MULTIPLIER 128
 #define DEFAULT_AUDIO_SAMPLE_RATE_HZ 48000
 
index c76e42c..6c82c3d 100644 (file)
@@ -568,6 +568,15 @@ static void _sde_hdmi_bridge_set_spd_infoframe(struct hdmi *hdmi,
        hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, packet_control);
 }
 
+static inline void _sde_hdmi_save_mode(struct hdmi *hdmi,
+       struct drm_display_mode *mode)
+{
+       struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
+       struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+       drm_mode_copy(&display->mode, mode);
+}
+
 static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
                 struct drm_display_mode *mode,
                 struct drm_display_mode *adjusted_mode)
@@ -640,6 +649,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
                DRM_DEBUG("hdmi setup info frame\n");
        }
        _sde_hdmi_bridge_setup_scrambler(hdmi, mode);
+
+       _sde_hdmi_save_mode(hdmi, mode);
 }
 
 static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = {
index b6cddee..119221e 100644 (file)
@@ -184,8 +184,7 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
                mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file);
 
        if (aspace) {
-               aspace->mmu->funcs->detach(aspace->mmu,
-                               iommu_ports, ARRAY_SIZE(iommu_ports));
+               aspace->mmu->funcs->detach(aspace->mmu);
                msm_gem_address_space_destroy(aspace);
        }
 }
@@ -202,8 +201,7 @@ static void mdp4_destroy(struct msm_kms *kms)
                drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo);
 
        if (aspace) {
-               aspace->mmu->funcs->detach(aspace->mmu,
-                               iommu_ports, ARRAY_SIZE(iommu_ports));
+               aspace->mmu->funcs->detach(aspace->mmu);
                msm_gem_address_space_put(aspace);
        }
 
@@ -416,10 +414,6 @@ fail:
        return ret;
 }
 
-static const char *iommu_ports[] = {
-               "mdp_port0_cb0", "mdp_port1_cb0",
-};
-
 struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 {
        struct platform_device *pdev = dev->platformdev;
@@ -515,15 +509,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        mdelay(16);
 
        if (config->iommu) {
-               struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu);
-
-               if (IS_ERR(mmu)) {
-                       ret = PTR_ERR(mmu);
-                       goto fail;
-               }
+               config->iommu->geometry.aperture_start = 0x1000;
+               config->iommu->geometry.aperture_end = 0xffffffff;
 
                aspace = msm_gem_address_space_create(&pdev->dev,
-                               mmu, "mdp4", 0x1000, 0xffffffff);
+                       config->iommu, MSM_IOMMU_DOMAIN_DEFAULT, "mdp4");
                if (IS_ERR(aspace)) {
                        ret = PTR_ERR(aspace);
                        goto fail;
@@ -531,8 +521,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 
                mdp4_kms->aspace = aspace;
 
-               ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
-                               ARRAY_SIZE(iommu_ports));
+               ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0);
                if (ret)
                        goto fail;
        } else {
index e4e69eb..4dbf456 100644 (file)
 #include "msm_mmu.h"
 #include "mdp5_kms.h"
 
-static const char *iommu_ports[] = {
-               "mdp_0",
-};
-
 static int mdp5_hw_init(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
@@ -613,8 +609,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 
                mdp5_kms->aspace = aspace;
 
-               ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
-                               ARRAY_SIZE(iommu_ports));
+               ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0);
                if (ret) {
                        dev_err(&pdev->dev, "failed to attach iommu: %d\n",
                                ret);
index 276329b..7d378f7 100644 (file)
@@ -1537,6 +1537,37 @@ static int msm_ioctl_deregister_event(struct drm_device *dev, void *data,
        return 0;
 }
 
+static int msm_ioctl_gem_sync(struct drm_device *dev, void *data,
+                            struct drm_file *file)
+{
+
+       struct drm_msm_gem_sync *arg = data;
+       int i;
+
+       for (i = 0; i < arg->nr_ops; i++) {
+               struct drm_msm_gem_syncop syncop;
+               struct drm_gem_object *obj;
+               int ret;
+               void __user *ptr =
+                       (void __user *)(uintptr_t)
+                               (arg->ops + (i * sizeof(syncop)));
+
+               ret = copy_from_user(&syncop, ptr, sizeof(syncop));
+               if (ret)
+                       return -EFAULT;
+
+               obj = drm_gem_object_lookup(dev, file, syncop.handle);
+               if (!obj)
+                       return -ENOENT;
+
+               msm_gem_sync(obj, syncop.op);
+
+               drm_gem_object_unreference_unlocked(obj);
+       }
+
+       return 0;
+}
+
 void msm_send_crtc_notification(struct drm_crtc *crtc,
                                struct drm_event *event, u8 *payload)
 {
@@ -1665,6 +1696,8 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
                          DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(MSM_COUNTER_READ, msm_ioctl_counter_read,
                          DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(MSM_GEM_SYNC, msm_ioctl_gem_sync,
+                         DRM_AUTH|DRM_RENDER_ALLOW),
 };
 
 static const struct vm_operations_struct vm_ops = {
index d2d118c..bd75a1b 100644 (file)
@@ -148,6 +148,7 @@ enum msm_mdp_conn_property {
        CONNECTOR_PROP_DST_Y,
        CONNECTOR_PROP_DST_W,
        CONNECTOR_PROP_DST_H,
+       CONNECTOR_PROP_PLL_DELTA,
 
        /* enum/bitmask properties */
        CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -412,7 +413,7 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
 /* For GPU and legacy display */
 struct msm_gem_address_space *
 msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
-               const char *name);
+               int type, const char *name);
 struct msm_gem_address_space *
 msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name,
                uint64_t start, uint64_t end);
@@ -469,6 +470,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
                uint32_t size, uint32_t flags);
 struct drm_gem_object *msm_gem_import(struct drm_device *dev,
                uint32_t size, struct sg_table *sgt);
+void msm_gem_sync(struct drm_gem_object *obj, u32 op);
 
 int msm_framebuffer_prepare(struct drm_framebuffer *fb,
                struct msm_gem_address_space *aspace);
index d1455fb..d35d03c 100644 (file)
@@ -546,6 +546,26 @@ int msm_gem_cpu_fini(struct drm_gem_object *obj)
        return 0;
 }
 
+void msm_gem_sync(struct drm_gem_object *obj, u32 op)
+{
+       struct drm_device *dev = obj->dev;
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+       if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
+               return;
+
+       switch (op) {
+       case MSM_GEM_SYNC_TO_CPU:
+               dma_sync_sg_for_cpu(dev->dev, msm_obj->sgt->sgl,
+                       msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+               break;
+       case MSM_GEM_SYNC_TO_DEV:
+               dma_sync_sg_for_device(dev->dev, msm_obj->sgt->sgl,
+                       msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+               break;
+       }
+}
+
 #ifdef CONFIG_DEBUG_FS
 void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
 {
index 2045dc3..0b19d11 100644 (file)
 /* Additional internal-use only BO flags: */
 #define MSM_BO_STOLEN        0x10000000    /* try to use stolen/splash memory */
 
-struct msm_gem_aspace_ops {
-       int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *,
-               struct sg_table *sgt, void *priv, unsigned int flags);
-
-       void (*unmap)(struct msm_gem_address_space *, struct msm_gem_vma *,
-               struct sg_table *sgt, void *priv);
-
-       void (*destroy)(struct msm_gem_address_space *);
-};
-
 struct msm_gem_address_space {
        const char *name;
        struct msm_mmu *mmu;
-       const struct msm_gem_aspace_ops *ops;
        struct kref kref;
+       struct drm_mm mm;
+       u64 va_len;
 };
 
 struct msm_gem_vma {
index 52fc814..8e0f15c 100644 (file)
@@ -82,13 +82,16 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                void __user *userptr =
                        to_user_ptr(args->bos + (i * sizeof(submit_bo)));
 
-               ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo));
-               if (unlikely(ret)) {
+               if (copy_from_user_inatomic(&submit_bo, userptr,
+                       sizeof(submit_bo))) {
                        pagefault_enable();
                        spin_unlock(&file->table_lock);
-                       ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
-                       if (ret)
+                       if (copy_from_user(&submit_bo, userptr,
+                               sizeof(submit_bo))) {
+                               ret = -EFAULT;
                                goto out;
+                       }
+
                        spin_lock(&file->table_lock);
                        pagefault_disable();
                }
@@ -283,8 +286,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
                uint32_t off;
                bool valid;
 
-               ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc));
-               if (ret)
+               if (copy_from_user(&submit_reloc, userptr,
+                       sizeof(submit_reloc)))
                        return -EFAULT;
 
                if (submit_reloc.submit_offset % 4) {
index a227f1b..47f7436 100644 (file)
@@ -25,8 +25,10 @@ msm_gem_address_space_destroy(struct kref *kref)
        struct msm_gem_address_space *aspace = container_of(kref,
                        struct msm_gem_address_space, kref);
 
-       if (aspace->ops->destroy)
-               aspace->ops->destroy(aspace);
+       if (aspace->va_len)
+               drm_mm_takedown(&aspace->mm);
+
+       aspace->mmu->funcs->destroy(aspace->mmu);
 
        kfree(aspace);
 }
@@ -37,57 +39,9 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace)
                kref_put(&aspace->kref, msm_gem_address_space_destroy);
 }
 
-/* SDE address space operations */
-static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt,
-               void *priv)
-{
-       struct dma_buf *buf = priv;
-
-       if (buf)
-               aspace->mmu->funcs->unmap_dma_buf(aspace->mmu,
-                       sgt, buf, DMA_BIDIRECTIONAL);
-       else
-               aspace->mmu->funcs->unmap_sg(aspace->mmu, sgt,
-                       DMA_BIDIRECTIONAL);
-
-       vma->iova = 0;
-
-       msm_gem_address_space_put(aspace);
-}
-
-
-static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt,
-               void *priv, unsigned int flags)
-{
-       struct dma_buf *buf = priv;
-       int ret;
-
-       if (buf)
-               ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf,
-                       DMA_BIDIRECTIONAL);
-       else
-               ret = aspace->mmu->funcs->map_sg(aspace->mmu, sgt,
-                       DMA_BIDIRECTIONAL);
-
-       if (!ret)
-               vma->iova = sg_dma_address(sgt->sgl);
-
-       /* Get a reference to the aspace to keep it around */
-       kref_get(&aspace->kref);
-
-       return ret;
-}
-
-static const struct msm_gem_aspace_ops smmu_aspace_ops = {
-       .map = smmu_aspace_map_vma,
-       .unmap = smmu_aspace_unmap_vma,
-};
-
-struct msm_gem_address_space *
-msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
-               const char *name)
+static struct msm_gem_address_space *
+msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
+               uint64_t start, uint64_t end)
 {
        struct msm_gem_address_space *aspace;
 
@@ -100,57 +54,28 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
 
        aspace->name = name;
        aspace->mmu = mmu;
-       aspace->ops = &smmu_aspace_ops;
-
-       kref_init(&aspace->kref);
-
-       return aspace;
-}
 
-/* GPU address space operations */
-struct msm_iommu_aspace {
-       struct msm_gem_address_space base;
-       struct drm_mm mm;
-};
+       aspace->va_len = end - start;
 
-#define to_iommu_aspace(aspace) \
-       ((struct msm_iommu_aspace *) \
-        container_of(aspace, struct msm_iommu_aspace, base))
+       if (aspace->va_len)
+               drm_mm_init(&aspace->mm, (start >> PAGE_SHIFT),
+                       (end >> PAGE_SHIFT) - 1);
 
-static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
-{
-       if (!vma->iova)
-               return;
-
-       if (aspace->mmu)
-               aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt);
-
-       drm_mm_remove_node(&vma->node);
-
-       vma->iova = 0;
+       kref_init(&aspace->kref);
 
-       msm_gem_address_space_put(aspace);
+       return aspace;
 }
 
-static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt, void *priv,
-               unsigned int flags)
+static int allocate_iova(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma, struct sg_table *sgt,
+               u64 *iova)
 {
-       struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
-       size_t size = 0;
        struct scatterlist *sg;
+       size_t size = 0;
        int ret, i;
-       int iommu_flags = IOMMU_READ;
-
-       if (!(flags & MSM_BO_GPU_READONLY))
-               iommu_flags |= IOMMU_WRITE;
 
-       if (flags & MSM_BO_PRIVILEGED)
-               iommu_flags |= IOMMU_PRIV;
-
-       if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(aspace->mmu))
-               iommu_flags |= IOMMU_CACHE;
+       if (!aspace->va_len)
+               return 0;
 
        if (WARN_ON(drm_mm_node_allocated(&vma->node)))
                return 0;
@@ -158,84 +83,73 @@ static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace,
        for_each_sg(sgt->sgl, sg, sgt->nents, i)
                size += sg->length + sg->offset;
 
-       ret = drm_mm_insert_node(&local->mm, &vma->node, size >> PAGE_SHIFT,
+       ret = drm_mm_insert_node(&aspace->mm, &vma->node, size >> PAGE_SHIFT,
                        0, DRM_MM_SEARCH_DEFAULT);
-       if (ret)
-               return ret;
-
-       vma->iova = vma->node.start << PAGE_SHIFT;
-
-       if (aspace->mmu)
-               ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt,
-                       iommu_flags);
 
-       /* Get a reference to the aspace to keep it around */
-       kref_get(&aspace->kref);
+       if (!ret && iova)
+               *iova = vma->node.start << PAGE_SHIFT;
 
        return ret;
 }
 
-static void iommu_aspace_destroy(struct msm_gem_address_space *aspace)
+int msm_gem_map_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma, struct sg_table *sgt,
+               void *priv, unsigned int flags)
 {
-       struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
-
-       drm_mm_takedown(&local->mm);
-       aspace->mmu->funcs->destroy(aspace->mmu);
-}
-
-static const struct msm_gem_aspace_ops msm_iommu_aspace_ops = {
-       .map = iommu_aspace_map_vma,
-       .unmap = iommu_aspace_unmap_vma,
-       .destroy = iommu_aspace_destroy,
-};
+       u64 iova = 0;
+       int ret;
 
-static struct msm_gem_address_space *
-msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
-               uint64_t start, uint64_t end)
-{
-       struct msm_iommu_aspace *local;
+       if (!aspace)
+               return -EINVAL;
 
-       if (!mmu)
-               return ERR_PTR(-EINVAL);
+       ret = allocate_iova(aspace, vma, sgt, &iova);
+       if (ret)
+               return ret;
 
-       local = kzalloc(sizeof(*local), GFP_KERNEL);
-       if (!local)
-               return ERR_PTR(-ENOMEM);
+       ret = aspace->mmu->funcs->map(aspace->mmu, iova, sgt,
+               flags, priv);
 
-       drm_mm_init(&local->mm, (start >> PAGE_SHIFT),
-               (end >> PAGE_SHIFT) - 1);
+       if (ret) {
+               if (drm_mm_node_allocated(&vma->node))
+                       drm_mm_remove_node(&vma->node);
 
-       local->base.name = name;
-       local->base.mmu = mmu;
-       local->base.ops = &msm_iommu_aspace_ops;
+               return ret;
+       }
 
-       kref_init(&local->base.kref);
+       vma->iova = sg_dma_address(sgt->sgl);
+       kref_get(&aspace->kref);
 
-       return &local->base;
+       return 0;
 }
 
-int msm_gem_map_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt,
-               void *priv, unsigned int flags)
+void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
 {
-       if (aspace && aspace->ops->map)
-               return aspace->ops->map(aspace, vma, sgt, priv, flags);
+       if (!aspace || !vma->iova)
+               return;
 
-       return -EINVAL;
+       aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv);
+
+       if (drm_mm_node_allocated(&vma->node))
+               drm_mm_remove_node(&vma->node);
+
+       vma->iova = 0;
+
+       msm_gem_address_space_put(aspace);
 }
 
-void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
+struct msm_gem_address_space *
+msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
+               const char *name)
 {
-       if (aspace && aspace->ops->unmap)
-               aspace->ops->unmap(aspace, vma, sgt, priv);
+       return msm_gem_address_space_new(mmu, name, 0, 0);
 }
 
 struct msm_gem_address_space *
 msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
-               const char *name)
+               int type, const char *name)
 {
-       struct msm_mmu *mmu = msm_iommu_new(dev, domain);
+       struct msm_mmu *mmu = msm_iommu_new(dev, type, domain);
 
        if (IS_ERR(mmu))
                return (struct msm_gem_address_space *) mmu;
index 5a505a8..2f01db8 100644 (file)
@@ -183,6 +183,9 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
+       if (gpu->aspace && gpu->aspace->mmu)
+               msm_mmu_enable(gpu->aspace->mmu);
+
        return 0;
 }
 
@@ -203,6 +206,9 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
        if (WARN_ON(gpu->active_cnt < 0))
                return -EINVAL;
 
+       if (gpu->aspace && gpu->aspace->mmu)
+               msm_mmu_disable(gpu->aspace->mmu);
+
        ret = disable_axi(gpu);
        if (ret)
                return ret;
@@ -837,7 +843,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
                dev_info(drm->dev, "%s: using IOMMU\n", name);
                gpu->aspace = msm_gem_address_space_create(&pdev->dev,
-                               iommu, "gpu");
+                               iommu, MSM_IOMMU_DOMAIN_USER, "gpu");
                if (IS_ERR(gpu->aspace)) {
                        ret = PTR_ERR(gpu->aspace);
                        dev_err(drm->dev, "failed to init iommu: %d\n", ret);
index 3fac423..29e2e59 100644 (file)
@@ -29,6 +29,9 @@
 struct msm_gem_submit;
 struct msm_gpu_perfcntr;
 
+#define MSM_GPU_DEFAULT_IONAME  "kgsl_3d0_reg_memory"
+#define MSM_GPU_DEFAULT_IRQNAME "kgsl_3d0_irq"
+
 struct msm_gpu_config {
        const char *ioname;
        const char *irqname;
index 3af2464..b52c475 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
+#include <soc/qcom/secure_buffer.h>
 #include "msm_drv.h"
 #include "msm_iommu.h"
 
@@ -27,31 +28,17 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
        return 0;
 }
 
-/*
- * Get and enable the IOMMU clocks so that we can make
- * sure they stay on the entire duration so that we can
- * safely change the pagetable from the GPU
- */
-static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
+static void iommu_get_clocks(struct msm_iommu *iommu, struct device *dev)
 {
-       struct msm_iommu *iommu = to_msm_iommu(mmu);
-       struct device *dev;
        struct property *prop;
        const char *name;
        int i = 0;
 
-       if (WARN_ON(!pdev))
-               return;
-
-       dev = &pdev->dev;
-
        iommu->nr_clocks =
                of_property_count_strings(dev->of_node, "clock-names");
 
-       if (iommu->nr_clocks < 0) {
-               iommu->nr_clocks = 0;
+       if (iommu->nr_clocks < 0)
                return;
-       }
 
        if (WARN_ON(iommu->nr_clocks > ARRAY_SIZE(iommu->clocks)))
                iommu->nr_clocks = ARRAY_SIZE(iommu->clocks);
@@ -60,78 +47,58 @@ static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
                if (i == iommu->nr_clocks)
                        break;
 
-               iommu->clocks[i] =  clk_get(dev, name);
-               if (iommu->clocks[i])
-                       clk_prepare_enable(iommu->clocks[i]);
-
-               i++;
+               iommu->clocks[i++] =  clk_get(dev, name);
        }
 }
 
-static int _attach_iommu_device(struct msm_mmu *mmu,
-               struct iommu_domain *domain, const char **names, int cnt)
+
+static void msm_iommu_clocks_enable(struct msm_mmu *mmu)
 {
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
        int i;
 
-       /* See if there is a iommus member in the current device.  If not, look
-        * for the names and see if there is one in there.
-        */
+       if (!iommu->nr_clocks)
+               iommu_get_clocks(iommu, mmu->dev->parent);
 
-       if (of_find_property(mmu->dev->of_node, "iommus", NULL))
-               return iommu_attach_device(domain, mmu->dev);
-
-       /* Look through the list of names for a target */
-       for (i = 0; i < cnt; i++) {
-               struct device_node *node =
-                       of_find_node_by_name(mmu->dev->of_node, names[i]);
-
-               if (!node)
-                       continue;
-
-               if (of_find_property(node, "iommus", NULL)) {
-                       struct platform_device *pdev;
-
-                       /* Get the platform device for the node */
-                       of_platform_populate(node->parent, NULL, NULL,
-                               mmu->dev);
-
-                       pdev = of_find_device_by_node(node);
-
-                       if (!pdev)
-                               continue;
-
-                       _get_iommu_clocks(mmu,
-                               of_find_device_by_node(node->parent));
+       for (i = 0; i < iommu->nr_clocks; i++) {
+               if (iommu->clocks[i])
+                       clk_prepare_enable(iommu->clocks[i]);
+       }
+}
 
-                       mmu->dev = &pdev->dev;
+static void msm_iommu_clocks_disable(struct msm_mmu *mmu)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       int i;
 
-                       return iommu_attach_device(domain, mmu->dev);
-               }
+       for (i = 0; i < iommu->nr_clocks; i++) {
+               if (iommu->clocks[i])
+                       clk_disable_unprepare(iommu->clocks[i]);
        }
+}
 
-       dev_err(mmu->dev, "Couldn't find a IOMMU device\n");
-       return -ENODEV;
+static int msm_iommu_attach(struct msm_mmu *mmu, const char **names,
+               int cnt)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+
+       return iommu_attach_device(iommu->domain, mmu->dev);
 }
 
-static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
+static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names,
+               int cnt)
 {
        struct msm_iommu *iommu = to_msm_iommu(mmu);
-       int val = 1, ret;
+       int ret, val = 1;
 
        /* Hope springs eternal */
-       iommu->allow_dynamic = true;
-
-       /* per-instance pagetables need TTBR1 support in the IOMMU driver */
-       ret = iommu_domain_set_attr(iommu->domain,
-               DOMAIN_ATTR_ENABLE_TTBR1, &val);
-       if (ret)
-               iommu->allow_dynamic = false;
+       iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain,
+               DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false;
 
        /* Mark the GPU as I/O coherent if it is supported */
        iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node);
 
-       /* Attach the device to the domain */
-       ret = _attach_iommu_device(mmu, iommu->domain, names, cnt);
+       ret = iommu_attach_device(iommu->domain, mmu->dev);
        if (ret)
                return ret;
 
@@ -176,17 +143,25 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names,
        return 0;
 }
 
+static int msm_iommu_attach_secure(struct msm_mmu *mmu, const char **names,
+               int cnt)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       int ret, vmid = VMID_CP_PIXEL;
+
+       ret = iommu_domain_set_attr(iommu->domain, DOMAIN_ATTR_SECURE_VMID,
+               &vmid);
+       if (ret)
+               return ret;
+
+       return iommu_attach_device(iommu->domain, mmu->dev);
+}
+
 static void msm_iommu_detach(struct msm_mmu *mmu)
 {
        struct msm_iommu *iommu = to_msm_iommu(mmu);
-       int i;
 
        iommu_detach_device(iommu->domain, mmu->dev);
-
-       for (i = 0; i < iommu->nr_clocks; i++) {
-               if (iommu->clocks[i])
-                       clk_disable(iommu->clocks[i]);
-       }
 }
 
 static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
@@ -196,69 +171,50 @@ static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
 }
 
 static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
-               struct sg_table *sgt, int prot)
+               struct sg_table *sgt, u32 flags, void *priv)
 {
        struct msm_iommu *iommu = to_msm_iommu(mmu);
        struct iommu_domain *domain = iommu->domain;
-       struct scatterlist *sg;
-       uint64_t da = iova;
-       unsigned int i, j;
        int ret;
+       u32 prot = IOMMU_READ;
 
        if (!domain || !sgt)
                return -EINVAL;
 
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               phys_addr_t pa = sg_phys(sg) - sg->offset;
-               size_t bytes = sg->length + sg->offset;
+       if (!(flags & MSM_BO_GPU_READONLY))
+               prot |= IOMMU_WRITE;
 
-               VERB("map[%d]: %016llx %pa(%zx)", i, iova, &pa, bytes);
+       if (flags & MSM_BO_PRIVILEGED)
+               prot |= IOMMU_PRIV;
 
-               ret = iommu_map(domain, da, pa, bytes, prot);
-               if (ret)
-                       goto fail;
+       if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(mmu))
+               prot |= IOMMU_CACHE;
 
-               da += bytes;
-       }
-
-       return 0;
-
-fail:
-       da = iova;
+       /* iommu_map_sg returns the number of bytes mapped */
+       ret =  iommu_map_sg(domain, iova, sgt->sgl, sgt->nents, prot);
+       if (ret)
+               sgt->sgl->dma_address = iova;
 
-       for_each_sg(sgt->sgl, sg, i, j) {
-               size_t bytes = sg->length + sg->offset;
-               iommu_unmap(domain, da, bytes);
-               da += bytes;
-       }
-       return ret;
+       return ret ? 0 : -ENOMEM;
 }
 
-static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova,
-               struct sg_table *sgt)
+static void msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova,
+               struct sg_table *sgt, void *priv)
 {
        struct msm_iommu *iommu = to_msm_iommu(mmu);
        struct iommu_domain *domain = iommu->domain;
        struct scatterlist *sg;
-       uint64_t da = iova;
-       int i;
+       size_t len = 0;
+       int ret, i;
 
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               size_t bytes = sg->length + sg->offset;
-               size_t unmapped;
+       for_each_sg(sgt->sgl, sg, sgt->nents, i)
+               len += sg->length;
 
-               unmapped = iommu_unmap(domain, da, bytes);
-               if (unmapped < bytes)
-                       return unmapped;
+       ret = iommu_unmap(domain, iova, len);
+       if (ret != len)
+               dev_warn(mmu->dev, "could not unmap iova %llx\n", iova);
 
-               VERB("unmap[%d]: %016llx(%zx)", i, iova, bytes);
-
-               BUG_ON(!PAGE_ALIGNED(bytes));
-
-               da += bytes;
-       }
-
-       return 0;
+       sgt->sgl->dma_address = 0;
 }
 
 static void msm_iommu_destroy(struct msm_mmu *mmu)
@@ -268,7 +224,30 @@ static void msm_iommu_destroy(struct msm_mmu *mmu)
        kfree(iommu);
 }
 
-static const struct msm_mmu_funcs funcs = {
+static struct device *find_context_bank(const char *name)
+{
+       struct device_node *node = of_find_node_by_name(NULL, name);
+       struct platform_device *pdev, *parent;
+
+       if (!node)
+               return ERR_PTR(-ENODEV);
+
+       if (!of_find_property(node, "iommus", NULL))
+               return ERR_PTR(-ENODEV);
+
+       /* Get the parent device */
+       parent = of_find_device_by_node(node->parent);
+
+       /* Populate the sub nodes */
+       of_platform_populate(parent->dev.of_node, NULL, NULL, &parent->dev);
+
+       /* Get the context bank device */
+       pdev = of_find_device_by_node(node);
+
+       return pdev ? &pdev->dev : ERR_PTR(-ENODEV);
+}
+
+static const struct msm_mmu_funcs default_funcs = {
                .attach = msm_iommu_attach,
                .detach = msm_iommu_detach,
                .map = msm_iommu_map,
@@ -276,6 +255,24 @@ static const struct msm_mmu_funcs funcs = {
                .destroy = msm_iommu_destroy,
 };
 
+static const struct msm_mmu_funcs user_funcs = {
+               .attach = msm_iommu_attach_user,
+               .detach = msm_iommu_detach,
+               .map = msm_iommu_map,
+               .unmap = msm_iommu_unmap,
+               .destroy = msm_iommu_destroy,
+               .enable = msm_iommu_clocks_enable,
+               .disable = msm_iommu_clocks_disable,
+};
+
+static const struct msm_mmu_funcs secure_funcs = {
+               .attach = msm_iommu_attach_secure,
+               .detach = msm_iommu_detach,
+               .map = msm_iommu_map,
+               .unmap = msm_iommu_unmap,
+               .destroy = msm_iommu_destroy,
+};
+
 static const struct msm_mmu_funcs dynamic_funcs = {
                .attach = msm_iommu_attach_dynamic,
                .detach = msm_iommu_detach_dynamic,
@@ -284,8 +281,26 @@ static const struct msm_mmu_funcs dynamic_funcs = {
                .destroy = msm_iommu_destroy,
 };
 
-struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
-               const struct msm_mmu_funcs *funcs)
+static const struct {
+       const char *cbname;
+       const struct msm_mmu_funcs *funcs;
+} msm_iommu_domains[] = {
+       [MSM_IOMMU_DOMAIN_DEFAULT] = {
+               .cbname = NULL,
+               .funcs = &default_funcs,
+       },
+       [MSM_IOMMU_DOMAIN_USER] = {
+               .cbname = "gfx3d_user",
+               .funcs = &user_funcs,
+       },
+       [MSM_IOMMU_DOMAIN_SECURE] = {
+               .cbname = "gfx3d_secure",
+               .funcs = &secure_funcs
+       },
+};
+
+static struct msm_mmu *iommu_create(struct device *dev,
+               struct iommu_domain *domain, const struct msm_mmu_funcs *funcs)
 {
        struct msm_iommu *iommu;
 
@@ -299,9 +314,23 @@ struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
 
        return &iommu->base;
 }
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
+
+struct msm_mmu *msm_iommu_new(struct device *parent,
+               enum msm_iommu_domain_type type, struct iommu_domain *domain)
 {
-       return _msm_iommu_new(dev, domain, &funcs);
+       struct device *dev = parent;
+
+       if (type >= ARRAY_SIZE(msm_iommu_domains) ||
+               !msm_iommu_domains[type].funcs)
+               return ERR_PTR(-ENODEV);
+
+       if (msm_iommu_domains[type].cbname) {
+               dev = find_context_bank(msm_iommu_domains[type].cbname);
+               if (IS_ERR(dev))
+                       return ERR_CAST(dev);
+       }
+
+       return iommu_create(dev, domain, msm_iommu_domains[type].funcs);
 }
 
 /*
@@ -326,7 +355,7 @@ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *base)
        if (!domain)
                return ERR_PTR(-ENODEV);
 
-       mmu = _msm_iommu_new(base->dev, domain, &dynamic_funcs);
+       mmu = iommu_create(base->dev, domain, &dynamic_funcs);
 
        if (IS_ERR(mmu)) {
                if (domain)
index 501f12b..033370c 100644 (file)
@@ -30,21 +30,22 @@ enum msm_mmu_domain_type {
        MSM_SMMU_DOMAIN_MAX,
 };
 
+enum msm_iommu_domain_type {
+       MSM_IOMMU_DOMAIN_DEFAULT,
+       MSM_IOMMU_DOMAIN_USER,
+       MSM_IOMMU_DOMAIN_SECURE,
+};
+
 struct msm_mmu_funcs {
        int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
        void (*detach)(struct msm_mmu *mmu);
        int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
-                       int prot);
-       int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt);
-       int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt,
-                       enum dma_data_direction dir);
-       void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt,
-               enum dma_data_direction dir);
-       int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt,
-                       struct dma_buf *dma_buf, int dir);
-       void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt,
-                       struct dma_buf *dma_buf, int dir);
+                       u32 flags, void *priv);
+       void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
+                       void *priv);
        void (*destroy)(struct msm_mmu *mmu);
+       void (*enable)(struct msm_mmu *mmu);
+       void (*disable)(struct msm_mmu *mmu);
 };
 
 struct msm_mmu {
@@ -59,9 +60,27 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
        mmu->funcs = funcs;
 }
 
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
+/* Create a new SDE mmu device */
 struct msm_mmu *msm_smmu_new(struct device *dev,
        enum msm_mmu_domain_type domain);
+
+/* Create a new legacy MDP4 or GPU mmu device */
+struct msm_mmu *msm_iommu_new(struct device *parent,
+               enum msm_iommu_domain_type type, struct iommu_domain *domain);
+
+/* Create a new dynamic domain for GPU */
 struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig);
 
+static inline void msm_mmu_enable(struct msm_mmu *mmu)
+{
+       if (mmu->funcs->enable)
+               mmu->funcs->enable(mmu);
+}
+
+static inline void msm_mmu_disable(struct msm_mmu *mmu)
+{
+       if (mmu->funcs->disable)
+               mmu->funcs->disable(mmu);
+}
+
 #endif /* __MSM_MMU_H__ */
index 5a9e472..5f3d1b6 100644 (file)
@@ -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
@@ -183,6 +183,55 @@ static void _msm_property_install_integer(struct msm_property_info *info,
        }
 }
 
+/**
+ * _msm_property_install_integer - install signed drm range property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default Property value
+ * @property_idx: Property index
+ * @force_dirty: Whether or not to filter 'dirty' status on unchanged values
+ */
+static void _msm_property_install_signed_integer(struct msm_property_info *info,
+               const char *name, int flags, int64_t min, int64_t max,
+               int64_t init, uint32_t property_idx, bool force_dirty)
+{
+       struct drm_property **prop;
+
+       if (!info)
+               return;
+
+       ++info->install_request;
+
+       if (!name || (property_idx >= info->property_count)) {
+               DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
+       } else {
+               prop = &info->property_array[property_idx];
+               /*
+                * Properties need to be attached to each drm object that
+                * uses them, but only need to be created once
+                */
+               if (*prop == 0) {
+                       *prop = drm_property_create_signed_range(info->dev,
+                                       flags, name, min, max);
+                       if (*prop == 0)
+                               DRM_ERROR("create %s property failed\n", name);
+               }
+
+               /* save init value for later */
+               info->property_data[property_idx].default_value = I642U64(init);
+               info->property_data[property_idx].force_dirty = force_dirty;
+
+               /* always attach property, if created */
+               if (*prop) {
+                       drm_object_attach_property(info->base, *prop, init);
+                       ++info->install_count;
+               }
+       }
+}
+
 void msm_property_install_range(struct msm_property_info *info,
                const char *name, int flags, uint64_t min, uint64_t max,
                uint64_t init, uint32_t property_idx)
@@ -199,6 +248,22 @@ void msm_property_install_volatile_range(struct msm_property_info *info,
                        min, max, init, property_idx, true);
 }
 
+void msm_property_install_signed_range(struct msm_property_info *info,
+               const char *name, int flags, int64_t min, int64_t max,
+               int64_t init, uint32_t property_idx)
+{
+       _msm_property_install_signed_integer(info, name, flags,
+                       min, max, init, property_idx, false);
+}
+
+void msm_property_install_volatile_signed_range(struct msm_property_info *info,
+               const char *name, int flags, int64_t min, int64_t max,
+               int64_t init, uint32_t property_idx)
+{
+       _msm_property_install_signed_integer(info, name, flags,
+                       min, max, init, property_idx, true);
+}
+
 void msm_property_install_rotation(struct msm_property_info *info,
                unsigned int supported_rotations, uint32_t property_idx)
 {
index dbe28bd..1430551 100644 (file)
@@ -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
@@ -208,6 +208,45 @@ void msm_property_install_volatile_range(struct msm_property_info *info,
                uint32_t property_idx);
 
 /**
+ * msm_property_install_signed_range - install signed drm range property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default Property value
+ * @property_idx: Property index
+ */
+void msm_property_install_signed_range(struct msm_property_info *info,
+               const char *name,
+               int flags,
+               int64_t min,
+               int64_t max,
+               int64_t init,
+               uint32_t property_idx);
+
+/**
+ * msm_property_install_volatile_signed_range - install signed range property
+ *     This function is similar to msm_property_install_range, but assumes
+ *     that the property is meant for holding user pointers or descriptors
+ *     that may reference volatile data without having an updated value.
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default Property value
+ * @property_idx: Property index
+ */
+void msm_property_install_volatile_signed_range(struct msm_property_info *info,
+               const char *name,
+               int flags,
+               int64_t min,
+               int64_t max,
+               int64_t init,
+               uint32_t property_idx);
+
+/**
  * msm_property_install_rotation - install standard drm rotation property
  * @info: Pointer to property info container struct
  * @supported_rotations: Bitmask of supported rotation values (see
index c99f51e..c2dd5f9 100644 (file)
@@ -53,6 +53,17 @@ struct msm_smmu_domain {
 #define to_msm_smmu(x) container_of(x, struct msm_smmu, base)
 #define msm_smmu_to_client(smmu) (smmu->client)
 
+
+static int msm_smmu_fault_handler(struct iommu_domain *iommu,
+        struct device *dev, unsigned long iova, int flags, void *arg)
+{
+
+       dev_info(dev, "%s: iova=0x%08lx, flags=0x%x, iommu=%pK\n", __func__,
+                       iova, flags, iommu);
+       return 0;
+}
+
+
 static int _msm_smmu_create_mapping(struct msm_smmu_client *client,
        const struct msm_smmu_domain *domain);
 
@@ -105,106 +116,34 @@ static void msm_smmu_detach(struct msm_mmu *mmu)
 }
 
 static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova,
-               struct sg_table *sgt, int prot)
+               struct sg_table *sgt, u32 flags, void *priv)
 {
        struct msm_smmu *smmu = to_msm_smmu(mmu);
        struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-       struct iommu_domain *domain;
-       struct scatterlist *sg;
-       uint64_t da = iova;
-       unsigned int i, j;
        int ret;
 
-       if (!client)
-               return -ENODEV;
-
-       domain = client->mmu_mapping->domain;
-       if (!domain || !sgt)
-               return -EINVAL;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               u32 pa = sg_phys(sg) - sg->offset;
-               size_t bytes = sg->length + sg->offset;
-
-               VERB("map[%d]: %16llx %08x(%zx)", i, iova, pa, bytes);
-
-               ret = iommu_map(domain, da, pa, bytes, prot);
-               if (ret)
-                       goto fail;
-
-               da += bytes;
-       }
-
-       return 0;
-
-fail:
-       da = iova;
+       if (priv)
+               ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents,
+                       DMA_BIDIRECTIONAL, priv);
+       else
+               ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents,
+                       DMA_BIDIRECTIONAL);
 
-       for_each_sg(sgt->sgl, sg, i, j) {
-               size_t bytes = sg->length + sg->offset;
-
-               iommu_unmap(domain, da, bytes);
-               da += bytes;
-       }
-       return ret;
+       return (ret != sgt->nents) ? -ENOMEM : 0;
 }
 
-static int msm_smmu_map_sg(struct msm_mmu *mmu, struct sg_table *sgt,
-               enum dma_data_direction dir)
+static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova,
+               struct sg_table *sgt, void *priv)
 {
        struct msm_smmu *smmu = to_msm_smmu(mmu);
        struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-       int ret;
 
-       ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, dir);
-       if (ret != sgt->nents)
-               return -ENOMEM;
-
-       return 0;
-}
-
-static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt,
-               enum dma_data_direction dir)
-{
-       struct msm_smmu *smmu = to_msm_smmu(mmu);
-       struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-
-       dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir);
-}
-
-static int msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova,
-               struct sg_table *sgt)
-{
-       struct msm_smmu *smmu = to_msm_smmu(mmu);
-       struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-       struct iommu_domain *domain;
-       struct scatterlist *sg;
-       uint64_t da = iova;
-       int i;
-
-       if (!client)
-               return -ENODEV;
-
-       domain = client->mmu_mapping->domain;
-       if (!domain || !sgt)
-               return -EINVAL;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               size_t bytes = sg->length + sg->offset;
-               size_t unmapped;
-
-               unmapped = iommu_unmap(domain, da, bytes);
-               if (unmapped < bytes)
-                       return unmapped;
-
-               VERB("unmap[%d]: %16llx(%zx)", i, iova, bytes);
-
-               WARN_ON(!PAGE_ALIGNED(bytes));
-
-               da += bytes;
-       }
-
-       return 0;
+       if (priv)
+               msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
+                       DMA_BIDIRECTIONAL, priv);
+       else
+               dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
+                       DMA_BIDIRECTIONAL);
 }
 
 static void msm_smmu_destroy(struct msm_mmu *mmu)
@@ -217,42 +156,11 @@ static void msm_smmu_destroy(struct msm_mmu *mmu)
        kfree(smmu);
 }
 
-static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
-                       struct dma_buf *dma_buf, int dir)
-{
-       struct msm_smmu *smmu = to_msm_smmu(mmu);
-       struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-       int ret;
-
-       ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, dir,
-                       dma_buf);
-       if (ret != sgt->nents) {
-               DRM_ERROR("dma map sg failed\n");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-
-static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
-                       struct dma_buf *dma_buf, int dir)
-{
-       struct msm_smmu *smmu = to_msm_smmu(mmu);
-       struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-
-       msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
-}
-
 static const struct msm_mmu_funcs funcs = {
        .attach = msm_smmu_attach,
        .detach = msm_smmu_detach,
        .map = msm_smmu_map,
-       .map_sg = msm_smmu_map_sg,
-       .unmap_sg = msm_smmu_unmap_sg,
        .unmap = msm_smmu_unmap,
-       .map_dma_buf = msm_smmu_map_dma_buf,
-       .unmap_dma_buf = msm_smmu_unmap_dma_buf,
        .destroy = msm_smmu_destroy,
 };
 
@@ -362,6 +270,7 @@ struct msm_mmu *msm_smmu_new(struct device *dev,
 {
        struct msm_smmu *smmu;
        struct device *client_dev;
+       struct msm_smmu_client *client;
 
        smmu = kzalloc(sizeof(*smmu), GFP_KERNEL);
        if (!smmu)
@@ -376,6 +285,11 @@ struct msm_mmu *msm_smmu_new(struct device *dev,
        smmu->client_dev = client_dev;
        msm_mmu_init(&smmu->base, dev, &funcs);
 
+       client = msm_smmu_to_client(smmu);
+       if (client)
+               iommu_set_fault_handler(client->mmu_mapping->domain,
+                                       msm_smmu_fault_handler, dev);
+
        return &smmu->base;
 }
 
index 247e135..fd560b2 100644 (file)
@@ -71,8 +71,8 @@ static inline bool _snapshot_header(struct msm_snapshot *snapshot,
  */
 #define SNAPSHOT_HEADER(_snapshot, _header, _id, _dwords) \
        _snapshot_header((_snapshot), \
-               (struct msm_snapshot_section_header *) &(header), \
-               sizeof(header), (_dwords) << 2, (_id))
+               (struct msm_snapshot_section_header *) &(_header), \
+               sizeof(_header), (_dwords) << 2, (_id))
 
 struct msm_gpu;
 
index 9f0adb9..7ad6f04 100644 (file)
@@ -118,4 +118,17 @@ struct msm_snapshot_shader {
        __u32 size;
 } __packed;
 
+#define SNAPSHOT_GPU_OBJECT_SHADER  1
+#define SNAPSHOT_GPU_OBJECT_IB      2
+#define SNAPSHOT_GPU_OBJECT_GENERIC 3
+#define SNAPSHOT_GPU_OBJECT_DRAW    4
+#define SNAPSHOT_GPU_OBJECT_GLOBAL  5
+
+struct msm_snapshot_gpu_object {
+       struct msm_snapshot_section_header header;
+       __u32 type;
+       __u64 gpuaddr;
+       __u64 pt_base;
+       __u64 size;
+} __packed;
 #endif
index 9034eeb..78df28a 100644 (file)
@@ -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
@@ -37,15 +37,15 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
        connector = bl_get_data(bd);
        c_conn = to_sde_connector(connector);
        display = (struct dsi_display *) c_conn->display;
-       if (brightness > display->panel->bl_config.bl_max_level)
-               brightness = display->panel->bl_config.bl_max_level;
+       if (brightness > display->panel[0]->bl_config.bl_max_level)
+               brightness = display->panel[0]->bl_config.bl_max_level;
 
        /* This maps UI brightness into driver backlight level with
         *        rounding
         */
        SDE_BRIGHT_TO_BL(bl_lvl, brightness,
-                       display->panel->bl_config.bl_max_level,
-                       display->panel->bl_config.brightness_max_level);
+                       display->panel[0]->bl_config.bl_max_level,
+                       display->panel[0]->bl_config.brightness_max_level);
 
        if (!bl_lvl && brightness)
                bl_lvl = 1;
@@ -85,7 +85,7 @@ int sde_backlight_setup(struct drm_connector *connector)
        switch (c_conn->connector_type) {
        case DRM_MODE_CONNECTOR_DSI:
                display = (struct dsi_display *) c_conn->display;
-               bl_config = &display->panel->bl_config;
+               bl_config = &display->panel[0]->bl_config;
                props.max_brightness = bl_config->brightness_max_level;
                props.brightness = bl_config->brightness_max_level;
                bd = backlight_device_register("sde-backlight",
index 31cf25a..7538927 100644 (file)
@@ -540,14 +540,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
                goto error_unregister_conn;
        }
 
-       if (c_conn->ops.set_backlight) {
-               rc = sde_backlight_setup(&c_conn->base);
-               if (rc) {
-                       pr_err("failed to setup backlight, rc=%d\n", rc);
-                       goto error_unregister_conn;
-               }
-       }
-
        /* create properties */
        msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
                        priv->conn_property, c_conn->property_data,
@@ -586,6 +578,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
        msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
                        0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
 
+       msm_property_install_volatile_signed_range(&c_conn->property_info,
+                       "PLL_DELTA", 0x0, INT_MIN, INT_MAX, 0,
+                       CONNECTOR_PROP_PLL_DELTA);
+
        /* enum/bitmask properties */
        msm_property_install_enum(&c_conn->property_info, "topology_name",
                        DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
index 23ffa9b..a59ec31 100644 (file)
@@ -718,12 +718,12 @@ static int _sde_format_populate_addrs_linear(
 {
        unsigned int i;
 
-       /* Can now check the pitches given vs pitches expected */
+       /* Update layout pitches from fb */
        for (i = 0; i < layout->num_planes; ++i) {
                if (layout->plane_pitch[i] != fb->pitches[i]) {
-                       DRM_ERROR("plane %u expected pitch %u, fb %u\n",
+                       SDE_DEBUG("plane %u expected pitch %u, fb %u\n",
                                i, layout->plane_pitch[i], fb->pitches[i]);
-                       return -EINVAL;
+                       layout->plane_pitch[i] = fb->pitches[i];
                }
        }
 
index 581918d..709c997 100644 (file)
 #define CREATE_TRACE_POINTS
 #include "sde_trace.h"
 
-static const char * const iommu_ports[] = {
-               "mdp_0",
-};
-
 /**
  * Controls size of event log buffer. Specified as a power of 2.
  */
@@ -416,6 +412,10 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
                return;
        }
 
+       ret = drm_crtc_vblank_get(crtc);
+       if (ret)
+               return;
+
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                if (encoder->crtc != crtc)
                        continue;
@@ -431,6 +431,8 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
                        break;
                }
        }
+
+       drm_crtc_vblank_put(crtc);
 }
 
 static void sde_kms_prepare_fence(struct msm_kms *kms,
@@ -598,6 +600,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
                .get_modes =  sde_hdmi_connector_get_modes,
                .mode_valid = sde_hdmi_mode_valid,
                .get_info =   sde_hdmi_get_info,
+               .set_property = sde_hdmi_set_property,
        };
        struct msm_display_info info = {0};
        struct drm_encoder *encoder;
@@ -1076,8 +1079,7 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms)
 
                sde_kms->aspace[i] = aspace;
 
-               ret = mmu->funcs->attach(mmu, (const char **)iommu_ports,
-                               ARRAY_SIZE(iommu_ports));
+               ret = mmu->funcs->attach(mmu, NULL, 0);
                if (ret) {
                        SDE_ERROR("failed to attach iommu %d: %d\n", i, ret);
                        msm_gem_address_space_put(aspace);
index ece9f41..7f8acb3 100644 (file)
@@ -714,7 +714,7 @@ nv4a_chipset = {
        .i2c = nv04_i2c_new,
        .imem = nv40_instmem_new,
        .mc = nv44_mc_new,
-       .mmu = nv44_mmu_new,
+       .mmu = nv04_mmu_new,
        .pci = nv40_pci_new,
        .therm = nv40_therm_new,
        .timer = nv41_timer_new,
index d4d8942..e55f830 100644 (file)
@@ -198,7 +198,7 @@ nv31_mpeg_intr(struct nvkm_engine *engine)
                }
 
                if (type == 0x00000010) {
-                       if (!nv31_mpeg_mthd(mpeg, mthd, data))
+                       if (nv31_mpeg_mthd(mpeg, mthd, data))
                                show &= ~0x01000000;
                }
        }
index d433cfa..36af0a8 100644 (file)
@@ -172,7 +172,7 @@ nv44_mpeg_intr(struct nvkm_engine *engine)
                }
 
                if (type == 0x00000010) {
-                       if (!nv44_mpeg_mthd(subdev->device, mthd, data))
+                       if (nv44_mpeg_mthd(subdev->device, mthd, data))
                                show &= ~0x01000000;
                }
        }
index 3531033..d684e2b 100644 (file)
@@ -213,8 +213,8 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
                        rbo->placement.num_busy_placement = 0;
                        for (i = 0; i < rbo->placement.num_placement; i++) {
                                if (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) {
-                                       if (rbo->placements[0].fpfn < fpfn)
-                                               rbo->placements[0].fpfn = fpfn;
+                                       if (rbo->placements[i].fpfn < fpfn)
+                                               rbo->placements[i].fpfn = fpfn;
                                } else {
                                        rbo->placement.busy_placement =
                                                &rbo->placements[i];
index 4f5fa8d..144367c 100644 (file)
@@ -179,7 +179,7 @@ int ttm_base_object_init(struct ttm_object_file *tfile,
        if (unlikely(ret != 0))
                goto out_err0;
 
-       ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+       ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
        if (unlikely(ret != 0))
                goto out_err1;
 
@@ -318,7 +318,8 @@ EXPORT_SYMBOL(ttm_ref_object_exists);
 
 int ttm_ref_object_add(struct ttm_object_file *tfile,
                       struct ttm_base_object *base,
-                      enum ttm_ref_type ref_type, bool *existed)
+                      enum ttm_ref_type ref_type, bool *existed,
+                      bool require_existed)
 {
        struct drm_open_hash *ht = &tfile->ref_hash[ref_type];
        struct ttm_ref_object *ref;
@@ -345,6 +346,9 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
                }
 
                rcu_read_unlock();
+               if (require_existed)
+                       return -EPERM;
+
                ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
                                           false, false);
                if (unlikely(ret != 0))
@@ -635,7 +639,7 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
        prime = (struct ttm_prime_object *) dma_buf->priv;
        base = &prime->base;
        *handle = base->hash.key;
-       ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+       ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
 
        dma_buf_put(dma_buf);
 
index 8e689b4..6c649f7 100644 (file)
@@ -539,7 +539,7 @@ int vmw_fence_create(struct vmw_fence_manager *fman,
                     struct vmw_fence_obj **p_fence)
 {
        struct vmw_fence_obj *fence;
-       int ret;
+       int ret;
 
        fence = kzalloc(sizeof(*fence), GFP_KERNEL);
        if (unlikely(fence == NULL))
@@ -702,6 +702,41 @@ void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
 }
 
 
+/**
+ * vmw_fence_obj_lookup - Look up a user-space fence object
+ *
+ * @tfile: A struct ttm_object_file identifying the caller.
+ * @handle: A handle identifying the fence object.
+ * @return: A struct vmw_user_fence base ttm object on success or
+ * an error pointer on failure.
+ *
+ * The fence object is looked up and type-checked. The caller needs
+ * to have opened the fence object first, but since that happens on
+ * creation and fence objects aren't shareable, that's not an
+ * issue currently.
+ */
+static struct ttm_base_object *
+vmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle)
+{
+       struct ttm_base_object *base = ttm_base_object_lookup(tfile, handle);
+
+       if (!base) {
+               pr_err("Invalid fence object handle 0x%08lx.\n",
+                      (unsigned long)handle);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (base->refcount_release != vmw_user_fence_base_release) {
+               pr_err("Invalid fence object handle 0x%08lx.\n",
+                      (unsigned long)handle);
+               ttm_base_object_unref(&base);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return base;
+}
+
+
 int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
                             struct drm_file *file_priv)
 {
@@ -727,13 +762,9 @@ int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
                arg->kernel_cookie = jiffies + wait_timeout;
        }
 
-       base = ttm_base_object_lookup(tfile, arg->handle);
-       if (unlikely(base == NULL)) {
-               printk(KERN_ERR "Wait invalid fence object handle "
-                      "0x%08lx.\n",
-                      (unsigned long)arg->handle);
-               return -EINVAL;
-       }
+       base = vmw_fence_obj_lookup(tfile, arg->handle);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        fence = &(container_of(base, struct vmw_user_fence, base)->fence);
 
@@ -772,13 +803,9 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
        struct vmw_private *dev_priv = vmw_priv(dev);
 
-       base = ttm_base_object_lookup(tfile, arg->handle);
-       if (unlikely(base == NULL)) {
-               printk(KERN_ERR "Fence signaled invalid fence object handle "
-                      "0x%08lx.\n",
-                      (unsigned long)arg->handle);
-               return -EINVAL;
-       }
+       base = vmw_fence_obj_lookup(tfile, arg->handle);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        fence = &(container_of(base, struct vmw_user_fence, base)->fence);
        fman = fman_from_fence(fence);
@@ -1093,6 +1120,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
                (struct drm_vmw_fence_event_arg *) data;
        struct vmw_fence_obj *fence = NULL;
        struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+       struct ttm_object_file *tfile = vmw_fp->tfile;
        struct drm_vmw_fence_rep __user *user_fence_rep =
                (struct drm_vmw_fence_rep __user *)(unsigned long)
                arg->fence_rep;
@@ -1106,24 +1134,18 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
         */
        if (arg->handle) {
                struct ttm_base_object *base =
-                       ttm_base_object_lookup_for_ref(dev_priv->tdev,
-                                                      arg->handle);
-
-               if (unlikely(base == NULL)) {
-                       DRM_ERROR("Fence event invalid fence object handle "
-                                 "0x%08lx.\n",
-                                 (unsigned long)arg->handle);
-                       return -EINVAL;
-               }
+                       vmw_fence_obj_lookup(tfile, arg->handle);
+
+               if (IS_ERR(base))
+                       return PTR_ERR(base);
+
                fence = &(container_of(base, struct vmw_user_fence,
                                       base)->fence);
                (void) vmw_fence_obj_reference(fence);
 
                if (user_fence_rep != NULL) {
-                       bool existed;
-
                        ret = ttm_ref_object_add(vmw_fp->tfile, base,
-                                                TTM_REF_USAGE, &existed);
+                                                TTM_REF_USAGE, NULL, false);
                        if (unlikely(ret != 0)) {
                                DRM_ERROR("Failed to reference a fence "
                                          "object.\n");
@@ -1166,8 +1188,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
        return 0;
 out_no_create:
        if (user_fence_rep != NULL)
-               ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
-                                         handle, TTM_REF_USAGE);
+               ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
 out_no_ref_obj:
        vmw_fence_obj_unreference(&fence);
        return ret;
index b8c6a03..5ec24fd 100644 (file)
@@ -114,8 +114,6 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
                param->value = dev_priv->has_dx;
                break;
        default:
-               DRM_ERROR("Illegal vmwgfx get param request: %d\n",
-                         param->param);
                return -EINVAL;
        }
 
@@ -186,7 +184,7 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
        bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS);
        struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
 
-       if (unlikely(arg->pad64 != 0)) {
+       if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) {
                DRM_ERROR("Illegal GET_3D_CAP argument.\n");
                return -EINVAL;
        }
index e57667c..dbca128 100644 (file)
@@ -591,7 +591,7 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo,
                return ret;
 
        ret = ttm_ref_object_add(tfile, &user_bo->prime.base,
-                                TTM_REF_SYNCCPU_WRITE, &existed);
+                                TTM_REF_SYNCCPU_WRITE, &existed, false);
        if (ret != 0 || existed)
                ttm_bo_synccpu_write_release(&user_bo->dma.base);
 
@@ -775,7 +775,7 @@ int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
 
        *handle = user_bo->prime.base.hash.key;
        return ttm_ref_object_add(tfile, &user_bo->prime.base,
-                                 TTM_REF_USAGE, NULL);
+                                 TTM_REF_USAGE, NULL, false);
 }
 
 /*
index 7d620e8..c9c04cc 100644 (file)
@@ -715,11 +715,14 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
                        128;
 
        num_sizes = 0;
-       for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
+       for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
+               if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS)
+                       return -EINVAL;
                num_sizes += req->mip_levels[i];
+       }
 
-       if (num_sizes > DRM_VMW_MAX_SURFACE_FACES *
-           DRM_VMW_MAX_MIP_LEVELS)
+       if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS ||
+           num_sizes == 0)
                return -EINVAL;
 
        size = vmw_user_surface_size + 128 +
@@ -904,17 +907,16 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
        uint32_t handle;
        struct ttm_base_object *base;
        int ret;
+       bool require_exist = false;
 
        if (handle_type == DRM_VMW_HANDLE_PRIME) {
                ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle);
                if (unlikely(ret != 0))
                        return ret;
        } else {
-               if (unlikely(drm_is_render_client(file_priv))) {
-                       DRM_ERROR("Render client refused legacy "
-                                 "surface reference.\n");
-                       return -EACCES;
-               }
+               if (unlikely(drm_is_render_client(file_priv)))
+                       require_exist = true;
+
                if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) {
                        DRM_ERROR("Locked master refused legacy "
                                  "surface reference.\n");
@@ -942,17 +944,14 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
 
                /*
                 * Make sure the surface creator has the same
-                * authenticating master.
+                * authenticating master, or is already registered with us.
                 */
                if (drm_is_primary_client(file_priv) &&
-                   user_srf->master != file_priv->master) {
-                       DRM_ERROR("Trying to reference surface outside of"
-                                 " master domain.\n");
-                       ret = -EACCES;
-                       goto out_bad_resource;
-               }
+                   user_srf->master != file_priv->master)
+                       require_exist = true;
 
-               ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+               ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL,
+                                        require_exist);
                if (unlikely(ret != 0)) {
                        DRM_ERROR("Could not add a reference to a surface.\n");
                        goto out_bad_resource;
index 6e2a0e3..fa95b4d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -560,16 +560,70 @@ static inline unsigned int _fixup_cache_range_op(unsigned int op)
 }
 #endif
 
-int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
-               uint64_t size, unsigned int op)
+static int kgsl_do_cache_op(struct page *page, void *addr,
+               uint64_t offset, uint64_t size, unsigned int op)
 {
+       void (*cache_op)(const void *, const void *);
+
        /*
-        * If the buffer is mapped in the kernel operate on that address
-        * otherwise use the user address
+        * The dmac_xxx_range functions handle addresses and sizes that
+        * are not aligned to the cacheline size correctly.
         */
+       switch (_fixup_cache_range_op(op)) {
+       case KGSL_CACHE_OP_FLUSH:
+               cache_op = dmac_flush_range;
+               break;
+       case KGSL_CACHE_OP_CLEAN:
+               cache_op = dmac_clean_range;
+               break;
+       case KGSL_CACHE_OP_INV:
+               cache_op = dmac_inv_range;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       void *addr = (memdesc->hostptr) ?
-               memdesc->hostptr : (void *) memdesc->useraddr;
+       if (page != NULL) {
+               unsigned long pfn = page_to_pfn(page) + offset / PAGE_SIZE;
+               /*
+                *  page_address() returns the kernel virtual address of page.
+                *  For high memory kernel virtual address exists only if page
+                *  has been mapped. So use a version of kmap rather than
+                *  page_address() for high memory.
+                */
+               if (PageHighMem(page)) {
+                       offset &= ~PAGE_MASK;
+
+                       do {
+                               unsigned int len = size;
+
+                               if (len + offset > PAGE_SIZE)
+                                       len = PAGE_SIZE - offset;
+
+                               page = pfn_to_page(pfn++);
+                               addr = kmap_atomic(page);
+                               cache_op(addr + offset, addr + offset + len);
+                               kunmap_atomic(addr);
+
+                               size -= len;
+                               offset = 0;
+                       } while (size);
+
+                       return 0;
+               }
+
+               addr = page_address(page);
+       }
+
+       cache_op(addr + offset, addr + offset + (size_t) size);
+       return 0;
+}
+
+int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
+               uint64_t size, unsigned int op)
+{
+       void *addr = NULL;
+       int ret = 0;
 
        if (size == 0 || size > UINT_MAX)
                return -EINVAL;
@@ -578,38 +632,59 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
        if ((offset + size < offset) || (offset + size < size))
                return -ERANGE;
 
-       /* Make sure the offset + size do not overflow the address */
-       if (addr + ((size_t) offset + (size_t) size) < addr)
-               return -ERANGE;
-
        /* Check that offset+length does not exceed memdesc->size */
        if (offset + size > memdesc->size)
                return -ERANGE;
 
-       /* Return quietly if the buffer isn't mapped on the CPU */
-       if (addr == NULL)
-               return 0;
+       if (memdesc->hostptr) {
+               addr = memdesc->hostptr;
+               /* Make sure the offset + size do not overflow the address */
+               if (addr + ((size_t) offset + (size_t) size) < addr)
+                       return -ERANGE;
 
-       addr = addr + offset;
+               ret = kgsl_do_cache_op(NULL, addr, offset, size, op);
+               return ret;
+       }
 
        /*
-        * The dmac_xxx_range functions handle addresses and sizes that
-        * are not aligned to the cacheline size correctly.
+        * If the buffer is not to mapped to kernel, perform cache
+        * operations after mapping to kernel.
         */
+       if (memdesc->sgt != NULL) {
+               struct scatterlist *sg;
+               unsigned int i, pos = 0;
 
-       switch (_fixup_cache_range_op(op)) {
-       case KGSL_CACHE_OP_FLUSH:
-               dmac_flush_range(addr, addr + (size_t) size);
-               break;
-       case KGSL_CACHE_OP_CLEAN:
-               dmac_clean_range(addr, addr + (size_t) size);
-               break;
-       case KGSL_CACHE_OP_INV:
-               dmac_inv_range(addr, addr + (size_t) size);
-               break;
-       }
+               for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
+                       uint64_t sg_offset, sg_left;
 
-       return 0;
+                       if (offset >= (pos + sg->length)) {
+                               pos += sg->length;
+                               continue;
+                       }
+                       sg_offset = offset > pos ? offset - pos : 0;
+                       sg_left = (sg->length - sg_offset > size) ? size :
+                                               sg->length - sg_offset;
+                       ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
+                                                               sg_left, op);
+                       size -= sg_left;
+                       if (size == 0)
+                               break;
+                       pos += sg->length;
+               }
+       } else if (memdesc->pages != NULL) {
+               addr = vmap(memdesc->pages, memdesc->page_count,
+                               VM_IOREMAP, pgprot_writecombine(PAGE_KERNEL));
+               if (addr == NULL)
+                       return -ENOMEM;
+
+               /* Make sure the offset + size do not overflow the address */
+               if (addr + ((size_t) offset + (size_t) size) < addr)
+                       return -ERANGE;
+
+               ret = kgsl_do_cache_op(NULL, addr, offset, size, op);
+               vunmap(addr);
+       }
+       return ret;
 }
 EXPORT_SYMBOL(kgsl_cache_range_op);
 
index 1ef37c7..d037454 100644 (file)
@@ -73,7 +73,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
        void *in, *out;
        unsigned long flags;
        int ret, err = 0;
-       unsigned long t;
        struct page *page;
 
        spin_lock_irqsave(&newchannel->lock, flags);
@@ -183,11 +182,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
                goto error1;
        }
 
-       t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
-       if (t == 0) {
-               err = -ETIMEDOUT;
-               goto error1;
-       }
+       wait_for_completion(&open_info->waitevent);
 
        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
        list_del(&open_info->msglistentry);
@@ -375,7 +370,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
        struct vmbus_channel_gpadl_header *gpadlmsg;
        struct vmbus_channel_gpadl_body *gpadl_body;
        struct vmbus_channel_msginfo *msginfo = NULL;
-       struct vmbus_channel_msginfo *submsginfo;
+       struct vmbus_channel_msginfo *submsginfo, *tmp;
        u32 msgcount;
        struct list_head *curr;
        u32 next_gpadl_handle;
@@ -437,6 +432,13 @@ cleanup:
        list_del(&msginfo->msglistentry);
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
+       if (msgcount > 1) {
+               list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist,
+                        msglistentry) {
+                       kfree(submsginfo);
+               }
+       }
+
        kfree(msginfo);
        return ret;
 }
index 4fc2e88..2bbc530 100644 (file)
@@ -429,7 +429,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
        union hv_connection_id conn_id;
        int ret = 0;
        int retries = 0;
-       u32 msec = 1;
+       u32 usec = 1;
 
        conn_id.asu32 = 0;
        conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -462,9 +462,9 @@ int vmbus_post_msg(void *buffer, size_t buflen)
                }
 
                retries++;
-               msleep(msec);
-               if (msec < 2048)
-                       msec *= 2;
+               udelay(usec);
+               if (usec < 2048)
+                       usec *= 2;
        }
        return ret;
 }
index ddbf7e7..8ce1f2e 100644 (file)
@@ -305,9 +305,10 @@ void hv_cleanup(bool crash)
 
                hypercall_msr.as_uint64 = 0;
                wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
-               if (!crash)
+               if (!crash) {
                        vfree(hv_context.tsc_page);
-               hv_context.tsc_page = NULL;
+                       hv_context.tsc_page = NULL;
+               }
        }
 #endif
 }
index 43af913..354da7f 100644 (file)
@@ -430,16 +430,27 @@ struct dm_info_msg {
  * currently hot added. We hot add in multiples of 128M
  * chunks; it is possible that we may not be able to bring
  * online all the pages in the region. The range
- * covered_end_pfn defines the pages that can
+ * covered_start_pfn:covered_end_pfn defines the pages that can
  * be brough online.
  */
 
 struct hv_hotadd_state {
        struct list_head list;
        unsigned long start_pfn;
+       unsigned long covered_start_pfn;
        unsigned long covered_end_pfn;
        unsigned long ha_end_pfn;
        unsigned long end_pfn;
+       /*
+        * A list of gaps.
+        */
+       struct list_head gap_list;
+};
+
+struct hv_hotadd_gap {
+       struct list_head list;
+       unsigned long start_pfn;
+       unsigned long end_pfn;
 };
 
 struct balloon_state {
@@ -595,18 +606,46 @@ static struct notifier_block hv_memory_nb = {
        .priority = 0
 };
 
+/* Check if the particular page is backed and can be onlined and online it. */
+static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
+{
+       unsigned long cur_start_pgp;
+       unsigned long cur_end_pgp;
+       struct hv_hotadd_gap *gap;
+
+       cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn);
+       cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+
+       /* The page is not backed. */
+       if (((unsigned long)pg < cur_start_pgp) ||
+           ((unsigned long)pg >= cur_end_pgp))
+               return;
+
+       /* Check for gaps. */
+       list_for_each_entry(gap, &has->gap_list, list) {
+               cur_start_pgp = (unsigned long)
+                       pfn_to_page(gap->start_pfn);
+               cur_end_pgp = (unsigned long)
+                       pfn_to_page(gap->end_pfn);
+               if (((unsigned long)pg >= cur_start_pgp) &&
+                   ((unsigned long)pg < cur_end_pgp)) {
+                       return;
+               }
+       }
 
-static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
+       /* This frame is currently backed; online the page. */
+       __online_page_set_limits(pg);
+       __online_page_increment_counters(pg);
+       __online_page_free(pg);
+}
+
+static void hv_bring_pgs_online(struct hv_hotadd_state *has,
+                               unsigned long start_pfn, unsigned long size)
 {
        int i;
 
-       for (i = 0; i < size; i++) {
-               struct page *pg;
-               pg = pfn_to_page(start_pfn + i);
-               __online_page_set_limits(pg);
-               __online_page_increment_counters(pg);
-               __online_page_free(pg);
-       }
+       for (i = 0; i < size; i++)
+               hv_page_online_one(has, pfn_to_page(start_pfn + i));
 }
 
 static void hv_mem_hot_add(unsigned long start, unsigned long size,
@@ -682,26 +721,25 @@ static void hv_online_page(struct page *pg)
 
        list_for_each(cur, &dm_device.ha_region_list) {
                has = list_entry(cur, struct hv_hotadd_state, list);
-               cur_start_pgp = (unsigned long)pfn_to_page(has->start_pfn);
-               cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+               cur_start_pgp = (unsigned long)
+                       pfn_to_page(has->start_pfn);
+               cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn);
 
-               if (((unsigned long)pg >= cur_start_pgp) &&
-                       ((unsigned long)pg < cur_end_pgp)) {
-                       /*
-                        * This frame is currently backed; online the
-                        * page.
-                        */
-                       __online_page_set_limits(pg);
-                       __online_page_increment_counters(pg);
-                       __online_page_free(pg);
-               }
+               /* The page belongs to a different HAS. */
+               if (((unsigned long)pg < cur_start_pgp) ||
+                   ((unsigned long)pg >= cur_end_pgp))
+                       continue;
+
+               hv_page_online_one(has, pg);
+               break;
        }
 }
 
-static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
+static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
 {
        struct list_head *cur;
        struct hv_hotadd_state *has;
+       struct hv_hotadd_gap *gap;
        unsigned long residual, new_inc;
 
        if (list_empty(&dm_device.ha_region_list))
@@ -716,6 +754,24 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
                 */
                if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
                        continue;
+
+               /*
+                * If the current start pfn is not where the covered_end
+                * is, create a gap and update covered_end_pfn.
+                */
+               if (has->covered_end_pfn != start_pfn) {
+                       gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC);
+                       if (!gap)
+                               return -ENOMEM;
+
+                       INIT_LIST_HEAD(&gap->list);
+                       gap->start_pfn = has->covered_end_pfn;
+                       gap->end_pfn = start_pfn;
+                       list_add_tail(&gap->list, &has->gap_list);
+
+                       has->covered_end_pfn = start_pfn;
+               }
+
                /*
                 * If the current hot add-request extends beyond
                 * our current limit; extend it.
@@ -732,19 +788,10 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
                        has->end_pfn += new_inc;
                }
 
-               /*
-                * If the current start pfn is not where the covered_end
-                * is, update it.
-                */
-
-               if (has->covered_end_pfn != start_pfn)
-                       has->covered_end_pfn = start_pfn;
-
-               return true;
-
+               return 1;
        }
 
-       return false;
+       return 0;
 }
 
 static unsigned long handle_pg_range(unsigned long pg_start,
@@ -783,6 +830,8 @@ static unsigned long handle_pg_range(unsigned long pg_start,
                        if (pgs_ol > pfn_cnt)
                                pgs_ol = pfn_cnt;
 
+                       has->covered_end_pfn +=  pgs_ol;
+                       pfn_cnt -= pgs_ol;
                        /*
                         * Check if the corresponding memory block is already
                         * online by checking its last previously backed page.
@@ -791,10 +840,8 @@ static unsigned long handle_pg_range(unsigned long pg_start,
                         */
                        if (start_pfn > has->start_pfn &&
                            !PageReserved(pfn_to_page(start_pfn - 1)))
-                               hv_bring_pgs_online(start_pfn, pgs_ol);
+                               hv_bring_pgs_online(has, start_pfn, pgs_ol);
 
-                       has->covered_end_pfn +=  pgs_ol;
-                       pfn_cnt -= pgs_ol;
                }
 
                if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
@@ -832,13 +879,19 @@ static unsigned long process_hot_add(unsigned long pg_start,
                                        unsigned long rg_size)
 {
        struct hv_hotadd_state *ha_region = NULL;
+       int covered;
 
        if (pfn_cnt == 0)
                return 0;
 
-       if (!dm_device.host_specified_ha_region)
-               if (pfn_covered(pg_start, pfn_cnt))
+       if (!dm_device.host_specified_ha_region) {
+               covered = pfn_covered(pg_start, pfn_cnt);
+               if (covered < 0)
+                       return 0;
+
+               if (covered)
                        goto do_pg_range;
+       }
 
        /*
         * If the host has specified a hot-add range; deal with it first.
@@ -850,10 +903,12 @@ static unsigned long process_hot_add(unsigned long pg_start,
                        return 0;
 
                INIT_LIST_HEAD(&ha_region->list);
+               INIT_LIST_HEAD(&ha_region->gap_list);
 
                list_add_tail(&ha_region->list, &dm_device.ha_region_list);
                ha_region->start_pfn = rg_start;
                ha_region->ha_end_pfn = rg_start;
+               ha_region->covered_start_pfn = pg_start;
                ha_region->covered_end_pfn = pg_start;
                ha_region->end_pfn = rg_start + rg_size;
        }
@@ -1581,6 +1636,7 @@ static int balloon_remove(struct hv_device *dev)
        struct hv_dynmem_device *dm = hv_get_drvdata(dev);
        struct list_head *cur, *tmp;
        struct hv_hotadd_state *has;
+       struct hv_hotadd_gap *gap, *tmp_gap;
 
        if (dm->num_pages_ballooned != 0)
                pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
@@ -1597,6 +1653,10 @@ static int balloon_remove(struct hv_device *dev)
 #endif
        list_for_each_safe(cur, tmp, &dm->ha_region_list) {
                has = list_entry(cur, struct hv_hotadd_state, list);
+               list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) {
+                       list_del(&gap->list);
+                       kfree(gap);
+               }
                list_del(&has->list);
                kfree(has);
        }
index acb3b30..90841ab 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
 #include <linux/regmap.h>
+#include <linux/delay.h>
 #include "bmg160.h"
 
 #define BMG160_IRQ_NAME                "bmg160_event"
@@ -53,6 +54,9 @@
 #define BMG160_NO_FILTER               0
 #define BMG160_DEF_BW                  100
 
+#define BMG160_GYRO_REG_RESET          0x14
+#define BMG160_GYRO_RESET_VAL          0xb6
+
 #define BMG160_REG_INT_MAP_0           0x17
 #define BMG160_INT_MAP_0_BIT_ANY       BIT(1)
 
@@ -186,6 +190,14 @@ static int bmg160_chip_init(struct bmg160_data *data)
        int ret;
        unsigned int val;
 
+       /*
+        * Reset chip to get it in a known good state. A delay of 30ms after
+        * reset is required according to the datasheet.
+        */
+       regmap_write(data->regmap, BMG160_GYRO_REG_RESET,
+                    BMG160_GYRO_RESET_VAL);
+       usleep_range(30000, 30700);
+
        ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val);
        if (ret < 0) {
                dev_err(data->dev, "Error reading reg_chip_id\n");
index 16f000a..3258baf 100644 (file)
@@ -189,6 +189,7 @@ static const struct xpad_device {
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
        { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 },
+       { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
        { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
        { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
        { 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 },
@@ -310,6 +311,7 @@ static struct usb_device_id xpad_table[] = {
        XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
        XPAD_XBOX360_VENDOR(0x24c6),            /* PowerA Controllers */
        XPAD_XBOX360_VENDOR(0x1532),            /* Razer Sabertooth */
+       XPAD_XBOXONE_VENDOR(0x1532),            /* Razer Wildcat */
        XPAD_XBOX360_VENDOR(0x15e4),            /* Numark X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x162e),            /* Joytech X-Box 360 controllers */
        { }
index 21898c3..599605a 100644 (file)
@@ -62,7 +62,7 @@ struct hbtp_data {
        u32 ts_pinctrl_seq_delay;
        u32 ddic_pinctrl_seq_delay[HBTP_PINCTRL_DDIC_SEQ_NUM];
        u32 fb_resume_seq_delay;
-       bool lcd_on;
+       int lcd_state;
        bool power_suspended;
        bool power_sync_enabled;
        bool power_sig_enabled;
@@ -108,6 +108,7 @@ static int fb_notifier_callback(struct notifier_block *self,
                                 unsigned long event, void *data)
 {
        int blank;
+       int lcd_state;
        struct fb_event *evdata = data;
        struct fb_info *fbi = NULL;
        struct hbtp_data *hbtp_data =
@@ -133,27 +134,32 @@ static int fb_notifier_callback(struct notifier_block *self,
                (event == FB_EARLY_EVENT_BLANK ||
                event == FB_R_EARLY_EVENT_BLANK)) {
                blank = *(int *)(evdata->data);
+               lcd_state = hbtp->lcd_state;
                if (event == FB_EARLY_EVENT_BLANK) {
-                       if (blank == FB_BLANK_UNBLANK) {
+                       if (blank <= FB_BLANK_NORMAL &&
+                               lcd_state == FB_BLANK_POWERDOWN) {
                                pr_debug("%s: receives EARLY_BLANK:UNBLANK\n",
                                        __func__);
-                               hbtp_data->lcd_on = true;
                                hbtp_fb_early_resume(hbtp_data);
-                       } else if (blank == FB_BLANK_POWERDOWN) {
+                       } else if (blank == FB_BLANK_POWERDOWN &&
+                                       lcd_state <= FB_BLANK_NORMAL) {
                                pr_debug("%s: receives EARLY_BLANK:POWERDOWN\n",
                                        __func__);
-                               hbtp_data->lcd_on = false;
+                       } else {
+                               pr_debug("%s: receives EARLY_BLANK:%d in %d state\n",
+                                       __func__, blank, lcd_state);
                        }
                } else if (event == FB_R_EARLY_EVENT_BLANK) {
-                       if (blank == FB_BLANK_UNBLANK) {
+                       if (blank <= FB_BLANK_NORMAL) {
                                pr_debug("%s: receives R_EARLY_BALNK:UNBLANK\n",
                                        __func__);
-                               hbtp_data->lcd_on = false;
                                hbtp_fb_suspend(hbtp_data);
                        } else if (blank == FB_BLANK_POWERDOWN) {
                                pr_debug("%s: receives R_EARLY_BALNK:POWERDOWN\n",
                                        __func__);
-                               hbtp_data->lcd_on = true;
+                       } else {
+                               pr_debug("%s: receives R_EARLY_BALNK:%d in %d state\n",
+                                       __func__, blank, lcd_state);
                        }
                }
        }
@@ -161,13 +167,20 @@ static int fb_notifier_callback(struct notifier_block *self,
        if (evdata->data && hbtp_data &&
                event == FB_EVENT_BLANK) {
                blank = *(int *)(evdata->data);
-               if (blank == FB_BLANK_POWERDOWN) {
+               lcd_state = hbtp->lcd_state;
+               if (blank == FB_BLANK_POWERDOWN &&
+                       lcd_state <= FB_BLANK_NORMAL) {
                        pr_debug("%s: receives BLANK:POWERDOWN\n", __func__);
                        hbtp_fb_suspend(hbtp_data);
-               } else if (blank == FB_BLANK_UNBLANK) {
+               } else if (blank <= FB_BLANK_NORMAL &&
+                               lcd_state == FB_BLANK_POWERDOWN) {
                        pr_debug("%s: receives BLANK:UNBLANK\n", __func__);
                        hbtp_fb_resume(hbtp_data);
+               } else {
+                       pr_debug("%s: receives BLANK:%d in %d state\n",
+                               __func__, blank, lcd_state);
                }
+               hbtp_data->lcd_state = blank;
        }
        return 0;
 }
index 43482ae..1a2b262 100644 (file)
@@ -1122,6 +1122,7 @@ 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 E547   0x470f00        50, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   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 (**)
@@ -1528,6 +1529,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
                },
        },
        {
+               /* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E547"),
+               },
+       },
+       {
                /* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
index 9d61eb1..c1cbec8 100644 (file)
@@ -355,18 +355,25 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf,
                return -EBADF;
        }
 
-       if (count == 0)
-               return 0;
+       mutex_lock(&(dev_data->file_mutex));
 
        if (count > (REG_ADDR_LIMIT - *f_pos))
                count = REG_ADDR_LIMIT - *f_pos;
 
-       tmpbuf = kzalloc(count + 1, GFP_KERNEL);
-       if (!tmpbuf)
-               return -ENOMEM;
-
-       mutex_lock(&(dev_data->file_mutex));
+       if (count == 0) {
+               retval = 0;
+               goto unlock;
+       }
 
+       if (*f_pos > REG_ADDR_LIMIT) {
+               retval = -EFAULT;
+               goto unlock;
+       }
+       tmpbuf = kzalloc(count + 1, GFP_KERNEL);
+       if (!tmpbuf) {
+               retval = -ENOMEM;
+               goto unlock;
+       }
        retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
                        *f_pos,
                        tmpbuf,
@@ -380,8 +387,9 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf,
                *f_pos += retval;
 
 clean_up:
-       mutex_unlock(&(dev_data->file_mutex));
        kfree(tmpbuf);
+unlock:
+       mutex_unlock(&(dev_data->file_mutex));
        return retval;
 }
 
@@ -405,21 +413,31 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf,
                return -EBADF;
        }
 
-       if (count == 0)
-               return 0;
+       mutex_lock(&(dev_data->file_mutex));
+
+       if (*f_pos > REG_ADDR_LIMIT) {
+               retval = -EFAULT;
+               goto unlock;
+       }
 
        if (count > (REG_ADDR_LIMIT - *f_pos))
                count = REG_ADDR_LIMIT - *f_pos;
 
+       if (count == 0) {
+               retval = 0;
+               goto unlock;
+       }
+
        tmpbuf = kzalloc(count + 1, GFP_KERNEL);
-       if (!tmpbuf)
-               return -ENOMEM;
+       if (!tmpbuf) {
+               retval = -ENOMEM;
+               goto unlock;
+       }
 
        if (copy_from_user(tmpbuf, buf, count)) {
-               kfree(tmpbuf);
-               return -EFAULT;
+               retval = -EFAULT;
+               goto clean_up;
        }
-       mutex_lock(&(dev_data->file_mutex));
 
        retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
                        *f_pos,
@@ -428,8 +446,10 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf,
        if (retval >= 0)
                *f_pos += retval;
 
-       mutex_unlock(&(dev_data->file_mutex));
+clean_up:
        kfree(tmpbuf);
+unlock:
+       mutex_unlock(&(dev_data->file_mutex));
        return retval;
 }
 
index f641118..7a504b1 100644 (file)
@@ -41,7 +41,7 @@ config IOMMU_IO_PGTABLE_LPAE_SELFTEST
 
 config IOMMU_IO_PGTABLE_FAST
        bool "Fast ARMv7/v8 Long Descriptor Format"
-       select IOMMU_IO_PGTABLE
+       depends on ARM64_DMA_USE_IOMMU
        help
           Enable support for a subset of the ARM long descriptor pagetable
          format.  This allocator achieves fast performance by
index 7922608..dc44b40 100644 (file)
@@ -522,6 +522,8 @@ static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain);
 static bool arm_smmu_has_secure_vmid(struct arm_smmu_domain *smmu_domain);
 static bool arm_smmu_is_iova_coherent(struct iommu_domain *domain,
                                        dma_addr_t iova);
+static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain,
+                                             dma_addr_t iova);
 
 static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain);
 
@@ -2190,8 +2192,8 @@ static int arm_smmu_attach_dynamic(struct iommu_domain *domain,
                                smmu->num_context_banks + 2,
                                MAX_ASID + 1, GFP_KERNEL);
        if (ret < 0) {
-               dev_err(smmu->dev, "dynamic ASID allocation failed: %d\n",
-                       ret);
+               dev_err_ratelimited(smmu->dev,
+                       "dynamic ASID allocation failed: %d\n", ret);
                goto out;
        }
 
@@ -2536,6 +2538,23 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
        return ret;
 }
 
+static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain,
+             dma_addr_t iova)
+{
+       uint64_t ret;
+       unsigned long flags;
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+       struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+       if (!ops)
+               return 0;
+
+       flags = arm_smmu_pgtbl_lock(smmu_domain);
+       ret = ops->iova_to_pte(ops, iova);
+       arm_smmu_pgtbl_unlock(smmu_domain, flags);
+       return ret;
+}
+
 static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova,
                           struct scatterlist *sg, unsigned int nents, int prot)
 {
@@ -3437,6 +3456,7 @@ static struct iommu_ops arm_smmu_ops = {
        .enable_config_clocks   = arm_smmu_enable_config_clocks,
        .disable_config_clocks  = arm_smmu_disable_config_clocks,
        .is_iova_coherent       = arm_smmu_is_iova_coherent,
+       .iova_to_pte = arm_smmu_iova_to_pte,
 };
 
 static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
index 6a8a949..2d2583c 100644 (file)
@@ -903,6 +903,19 @@ found_translation:
        return 0;
 }
 
+static uint64_t arm_lpae_iova_get_pte(struct io_pgtable_ops *ops,
+                                        unsigned long iova)
+{
+       struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+       arm_lpae_iopte pte;
+       int lvl;
+
+       if (!arm_lpae_iova_to_pte(data, iova, &lvl, &pte))
+               return pte;
+
+       return 0;
+}
+
 static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
                                         unsigned long iova)
 {
@@ -1033,6 +1046,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
                .unmap          = arm_lpae_unmap,
                .iova_to_phys   = arm_lpae_iova_to_phys,
                .is_iova_coherent = arm_lpae_is_iova_coherent,
+               .iova_to_pte    = arm_lpae_iova_get_pte,
        };
 
        return data;
index e6939c2..2cf2135 100644 (file)
@@ -124,6 +124,8 @@ struct io_pgtable_ops {
                                    unsigned long iova);
        bool (*is_iova_coherent)(struct io_pgtable_ops *ops,
                                unsigned long iova);
+       uint64_t (*iova_to_pte)(struct io_pgtable_ops *ops,
+                   unsigned long iova);
 
 };
 
index ffeb47c..776e06f 100644 (file)
@@ -470,6 +470,7 @@ static inline void iommu_debug_destroy_tracking(void) { }
 static LIST_HEAD(iommu_debug_devices);
 static struct dentry *debugfs_tests_dir;
 static u32 iters_per_op = 1;
+static void *virt_addr;
 
 struct iommu_debug_device {
        struct device *dev;
@@ -1537,6 +1538,68 @@ out_domain_free:
        return -EIO;
 }
 
+static ssize_t __iommu_debug_dma_attach_write(struct file *file,
+                                         const char __user *ubuf,
+                                         size_t count, loff_t *offset)
+{
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+       struct dma_iommu_mapping *dma_mapping;
+       ssize_t retval = -EINVAL;
+       int val;
+
+       if (kstrtoint_from_user(ubuf, count, 0, &val)) {
+               pr_err("Invalid format. Expected a hex or decimal integer");
+               retval = -EFAULT;
+               goto out;
+       }
+
+       if (val) {
+               if (dev->archdata.mapping)
+                       if (dev->archdata.mapping->domain) {
+                               pr_err("Already attached.\n");
+                               retval = -EINVAL;
+                               goto out;
+                       }
+               if (WARN(dev->archdata.iommu,
+                       "Attachment tracking out of sync with device\n")) {
+                       retval = -EINVAL;
+                       goto out;
+               }
+
+               dma_mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
+                               (SZ_1G * 4ULL));
+
+               if (!dma_mapping)
+                       goto out;
+
+               if (arm_iommu_attach_device(dev, dma_mapping))
+                       goto out_release_mapping;
+               pr_err("Attached\n");
+       } else {
+               if (!dev->archdata.mapping) {
+                       pr_err("No mapping. Did you already attach?\n");
+                       retval = -EINVAL;
+                       goto out;
+               }
+               if (!dev->archdata.mapping->domain) {
+                       pr_err("No domain. Did you already attach?\n");
+                       retval = -EINVAL;
+                       goto out;
+               }
+               arm_iommu_detach_device(dev);
+               arm_iommu_release_mapping(dev->archdata.mapping);
+               pr_err("Detached\n");
+       }
+       retval = count;
+       return retval;
+
+out_release_mapping:
+       arm_iommu_release_mapping(dma_mapping);
+out:
+       return retval;
+}
+
 static ssize_t __iommu_debug_attach_write(struct file *file,
                                          const char __user *ubuf,
                                          size_t count, loff_t *offset,
@@ -1585,6 +1648,79 @@ out:
        return retval;
 }
 
+static ssize_t iommu_debug_dma_attach_write(struct file *file,
+                                         const char __user *ubuf,
+                                         size_t count, loff_t *offset)
+{
+       return __iommu_debug_dma_attach_write(file, ubuf, count, offset);
+
+}
+
+static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf,
+                                      size_t count, loff_t *offset)
+{
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+       char c[2];
+
+       if (*offset)
+               return 0;
+
+       if (!dev->archdata.mapping)
+               c[0] = '0';
+       else
+               c[0] = dev->archdata.mapping->domain ? '1' : '0';
+
+       c[1] = '\n';
+       if (copy_to_user(ubuf, &c, 2)) {
+               pr_err("copy_to_user failed\n");
+               return -EFAULT;
+       }
+       *offset = 1;            /* non-zero means we're done */
+
+       return 2;
+}
+
+static const struct file_operations iommu_debug_dma_attach_fops = {
+       .open   = simple_open,
+       .write  = iommu_debug_dma_attach_write,
+       .read   = iommu_debug_dma_attach_read,
+};
+
+static ssize_t iommu_debug_virt_addr_read(struct file *file, char __user *ubuf,
+                                    size_t count, loff_t *offset)
+{
+       char buf[100];
+       ssize_t retval;
+       size_t buflen;
+
+       if (*offset)
+               return 0;
+
+       memset(buf, 0, 100);
+
+       if (!virt_addr)
+               strlcpy(buf, "FAIL\n", 100);
+       else
+               snprintf(buf, 100, "0x%pK\n", virt_addr);
+
+       buflen = strlen(buf);
+       if (copy_to_user(ubuf, buf, buflen)) {
+               pr_err("Couldn't copy_to_user\n");
+               retval = -EFAULT;
+       } else {
+               *offset = 1;    /* non-zero means we're done */
+               retval = buflen;
+       }
+
+       return retval;
+}
+
+static const struct file_operations iommu_debug_virt_addr_fops = {
+       .open   = simple_open,
+       .read   = iommu_debug_virt_addr_read,
+};
+
 static ssize_t iommu_debug_attach_write(struct file *file,
                                          const char __user *ubuf,
                                          size_t count, loff_t *offset)
@@ -1635,6 +1771,75 @@ static const struct file_operations iommu_debug_secure_attach_fops = {
        .read   = iommu_debug_attach_read,
 };
 
+static ssize_t iommu_debug_pte_write(struct file *file,
+                                     const char __user *ubuf,
+                                     size_t count, loff_t *offset)
+{
+       struct iommu_debug_device *ddev = file->private_data;
+       dma_addr_t iova;
+
+       if (kstrtox_from_user(ubuf, count, 0, &iova)) {
+               pr_err("Invalid format for iova\n");
+               ddev->iova = 0;
+               return -EINVAL;
+       }
+
+       ddev->iova = iova;
+       pr_err("Saved iova=%pa for future PTE commands\n", &iova);
+       return count;
+}
+
+
+static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf,
+                                    size_t count, loff_t *offset)
+{
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+       uint64_t pte;
+       char buf[100];
+       ssize_t retval;
+       size_t buflen;
+
+       if (!dev->archdata.mapping) {
+               pr_err("No mapping. Did you already attach?\n");
+               return -EINVAL;
+       }
+       if (!dev->archdata.mapping->domain) {
+               pr_err("No domain. Did you already attach?\n");
+               return -EINVAL;
+       }
+
+       if (*offset)
+               return 0;
+
+       memset(buf, 0, 100);
+
+       pte = iommu_iova_to_pte(dev->archdata.mapping->domain,
+                       ddev->iova);
+
+       if (!pte)
+               strlcpy(buf, "FAIL\n", 100);
+       else
+               snprintf(buf, 100, "pte=%016llx\n", pte);
+
+       buflen = strlen(buf);
+       if (copy_to_user(ubuf, buf, buflen)) {
+               pr_err("Couldn't copy_to_user\n");
+               retval = -EFAULT;
+       } else {
+               *offset = 1;    /* non-zero means we're done */
+               retval = buflen;
+       }
+
+       return retval;
+}
+
+static const struct file_operations iommu_debug_pte_fops = {
+       .open   = simple_open,
+       .write  = iommu_debug_pte_write,
+       .read   = iommu_debug_pte_read,
+};
+
 static ssize_t iommu_debug_atos_write(struct file *file,
                                      const char __user *ubuf,
                                      size_t count, loff_t *offset)
@@ -1673,10 +1878,14 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
        memset(buf, 0, 100);
 
        phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
-       if (!phys)
+       if (!phys) {
                strlcpy(buf, "FAIL\n", 100);
-       else
+               phys = iommu_iova_to_phys(ddev->domain, ddev->iova);
+               dev_err(ddev->dev, "ATOS for %pa failed. Software walk returned: %pa\n",
+                       &ddev->iova, &phys);
+       } else {
                snprintf(buf, 100, "%pa\n", &phys);
+       }
 
        buflen = strlen(buf);
        if (copy_to_user(ubuf, buf, buflen)) {
@@ -1696,6 +1905,55 @@ static const struct file_operations iommu_debug_atos_fops = {
        .read   = iommu_debug_atos_read,
 };
 
+static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf,
+                                    size_t count, loff_t *offset)
+{
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+       phys_addr_t phys;
+       char buf[100];
+       ssize_t retval;
+       size_t buflen;
+
+       if (!dev->archdata.mapping) {
+               pr_err("No mapping. Did you already attach?\n");
+               return -EINVAL;
+       }
+       if (!dev->archdata.mapping->domain) {
+               pr_err("No domain. Did you already attach?\n");
+               return -EINVAL;
+       }
+
+       if (*offset)
+               return 0;
+
+       memset(buf, 0, 100);
+
+       phys = iommu_iova_to_phys_hard(dev->archdata.mapping->domain,
+                       ddev->iova);
+       if (!phys)
+               strlcpy(buf, "FAIL\n", 100);
+       else
+               snprintf(buf, 100, "%pa\n", &phys);
+
+       buflen = strlen(buf);
+       if (copy_to_user(ubuf, buf, buflen)) {
+               pr_err("Couldn't copy_to_user\n");
+               retval = -EFAULT;
+       } else {
+               *offset = 1;    /* non-zero means we're done */
+               retval = buflen;
+       }
+
+       return retval;
+}
+
+static const struct file_operations iommu_debug_dma_atos_fops = {
+       .open   = simple_open,
+       .write  = iommu_debug_atos_write,
+       .read   = iommu_debug_dma_atos_read,
+};
+
 static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
                                     size_t count, loff_t *offset)
 {
@@ -1776,6 +2034,152 @@ static const struct file_operations iommu_debug_map_fops = {
        .write  = iommu_debug_map_write,
 };
 
+static ssize_t iommu_debug_dma_map_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *offset)
+{
+       ssize_t retval = -EINVAL;
+       int ret;
+       char *comma1, *comma2;
+       char buf[100];
+       unsigned long addr;
+       void *v_addr;
+       dma_addr_t iova;
+       size_t size;
+       unsigned int attr;
+       struct dma_attrs coherent_attr;
+       struct dma_attrs *dma_attrs = &coherent_attr;
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+
+       init_dma_attrs(dma_attrs);
+
+       if (count >= 100) {
+               pr_err("Value too large\n");
+               return -EINVAL;
+       }
+
+       if (!dev->archdata.mapping) {
+               pr_err("No mapping. Did you already attach?\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       if (!dev->archdata.mapping->domain) {
+               pr_err("No domain. Did you already attach?\n");
+               retval = -EINVAL;
+               goto out;
+       }
+
+       memset(buf, 0, 100);
+
+       if (copy_from_user(buf, ubuf, count)) {
+               pr_err("Couldn't copy from user\n");
+               retval = -EFAULT;
+               goto out;
+       }
+
+       comma1 = strnchr(buf, count, ',');
+       if (!comma1)
+               goto invalid_format;
+
+       comma2 = strnchr(comma1 + 1, count, ',');
+       if (!comma2)
+               goto invalid_format;
+
+       *comma1 = *comma2 = '\0';
+
+       if (kstrtoul(buf, 0, &addr))
+               goto invalid_format;
+       v_addr = (void *)addr;
+
+       if (kstrtosize_t(comma1 + 1, 0, &size))
+               goto invalid_format;
+
+       if (kstrtouint(comma2 + 1, 0, &attr))
+               goto invalid_format;
+
+       if (v_addr < virt_addr || v_addr > (virt_addr + SZ_1M - 1))
+               goto invalid_addr;
+
+       if (attr == 0)
+               dma_attrs = NULL;
+       else if (attr == 1)
+               dma_set_attr(DMA_ATTR_FORCE_COHERENT, dma_attrs);
+       else if (attr == 2)
+               dma_set_attr(DMA_ATTR_FORCE_NON_COHERENT, dma_attrs);
+       else
+               goto invalid_format;
+
+       iova = dma_map_single_attrs(dev, v_addr, size,
+                                       DMA_TO_DEVICE, dma_attrs);
+
+       if (dma_mapping_error(dev, iova)) {
+               pr_err("Failed to perform dma_map_single\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       retval = count;
+       pr_err("Mapped 0x%p to %pa (len=0x%zx)\n",
+                       v_addr, &iova, size);
+       ddev->iova = iova;
+               pr_err("Saved iova=%pa for future PTE commands\n", &iova);
+out:
+       return retval;
+
+invalid_format:
+       pr_err("Invalid format. Expected: addr,len,dma attr where 'dma attr' is\n0: normal mapping\n1: force coherent\n2: force non-cohernet\n");
+       return retval;
+
+invalid_addr:
+       pr_err("Invalid addr given! Address should be within 1MB size from start addr returned by doing 'cat virt_addr'.\n");
+       return retval;
+}
+
+static ssize_t iommu_debug_dma_map_read(struct file *file, char __user *ubuf,
+            size_t count, loff_t *offset)
+{
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+       char buf[100];
+       ssize_t retval;
+       size_t buflen;
+       dma_addr_t iova;
+
+       if (!dev->archdata.mapping) {
+               pr_err("No mapping. Did you already attach?\n");
+               return -EINVAL;
+       }
+       if (!dev->archdata.mapping->domain) {
+               pr_err("No domain. Did you already attach?\n");
+               return -EINVAL;
+       }
+
+       if (*offset)
+               return 0;
+
+       memset(buf, 0, 100);
+
+       iova = ddev->iova;
+       snprintf(buf, 100, "%pa\n", &iova);
+
+       buflen = strlen(buf);
+       if (copy_to_user(ubuf, buf, buflen)) {
+               pr_err("Couldn't copy_to_user\n");
+               retval = -EFAULT;
+       } else {
+               *offset = 1;    /* non-zero means we're done */
+               retval = buflen;
+       }
+
+       return retval;
+}
+
+static const struct file_operations iommu_debug_dma_map_fops = {
+       .open   = simple_open,
+       .write  = iommu_debug_dma_map_write,
+       .read   = iommu_debug_dma_map_read,
+};
+
 static ssize_t iommu_debug_unmap_write(struct file *file,
                                       const char __user *ubuf,
                                       size_t count, loff_t *offset)
@@ -1841,6 +2245,92 @@ static const struct file_operations iommu_debug_unmap_fops = {
        .write  = iommu_debug_unmap_write,
 };
 
+static ssize_t iommu_debug_dma_unmap_write(struct file *file,
+                                      const char __user *ubuf,
+                                      size_t count, loff_t *offset)
+{
+       ssize_t retval = 0;
+       char *comma1, *comma2;
+       char buf[100];
+       size_t size;
+       unsigned int attr;
+       dma_addr_t iova;
+       struct dma_attrs coherent_attr;
+       struct dma_attrs *dma_attrs = &coherent_attr;
+       struct iommu_debug_device *ddev = file->private_data;
+       struct device *dev = ddev->dev;
+
+       init_dma_attrs(dma_attrs);
+
+       if (count >= 100) {
+               pr_err("Value too large\n");
+               return -EINVAL;
+       }
+
+       if (!dev->archdata.mapping) {
+               pr_err("No mapping. Did you already attach?\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       if (!dev->archdata.mapping->domain) {
+               pr_err("No domain. Did you already attach?\n");
+               retval = -EINVAL;
+               goto out;
+       }
+
+       memset(buf, 0, 100);
+
+       if (copy_from_user(buf, ubuf, count)) {
+               pr_err("Couldn't copy from user\n");
+               retval = -EFAULT;
+               goto out;
+       }
+
+       comma1 = strnchr(buf, count, ',');
+       if (!comma1)
+               goto invalid_format;
+
+       comma2 = strnchr(comma1 + 1, count, ',');
+       if (!comma2)
+               goto invalid_format;
+
+       *comma1 = *comma2 = '\0';
+
+       if (kstrtoux(buf, 0, &iova))
+               goto invalid_format;
+
+       if (kstrtosize_t(comma1 + 1, 0, &size))
+               goto invalid_format;
+
+       if (kstrtouint(comma2 + 1, 0, &attr))
+               goto invalid_format;
+
+       if (attr == 0)
+               dma_attrs = NULL;
+       else if (attr == 1)
+               dma_set_attr(DMA_ATTR_FORCE_COHERENT, dma_attrs);
+       else if (attr == 2)
+               dma_set_attr(DMA_ATTR_FORCE_NON_COHERENT, dma_attrs);
+       else
+               goto invalid_format;
+
+       dma_unmap_single_attrs(dev, iova, size, DMA_TO_DEVICE, dma_attrs);
+
+       retval = count;
+       pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
+out:
+       return retval;
+
+invalid_format:
+       pr_err("Invalid format. Expected: iova,len, dma attr\n");
+       return retval;
+}
+
+static const struct file_operations iommu_debug_dma_unmap_fops = {
+       .open   = simple_open,
+       .write  = iommu_debug_dma_unmap_write,
+};
+
 static ssize_t iommu_debug_config_clocks_write(struct file *file,
                                               const char __user *ubuf,
                                               size_t count, loff_t *offset)
@@ -1919,6 +2409,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
                goto err_rmdir;
        }
 
+       if (!debugfs_create_file("virt_addr", S_IRUSR, dir, ddev,
+                               &iommu_debug_virt_addr_fops)) {
+               pr_err("Couldn't create iommu/devices/%s/virt_addr debugfs file\n",
+                      name);
+               goto err_rmdir;
+       }
+
        if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
                                 &iommu_debug_profiling_fops)) {
                pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
@@ -1961,6 +2458,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
                goto err_rmdir;
        }
 
+       if (!debugfs_create_file("dma_attach", S_IRUSR, dir, ddev,
+                                &iommu_debug_dma_attach_fops)) {
+               pr_err("Couldn't create iommu/devices/%s/dma_attach debugfs file\n",
+                              name);
+               goto err_rmdir;
+       }
+
        if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
                                 &iommu_debug_attach_fops)) {
                pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
@@ -1982,6 +2486,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
                goto err_rmdir;
        }
 
+       if (!debugfs_create_file("dma_atos", S_IWUSR, dir, ddev,
+                                &iommu_debug_dma_atos_fops)) {
+               pr_err("Couldn't create iommu/devices/%s/dma_atos debugfs file\n",
+                              name);
+               goto err_rmdir;
+       }
+
        if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
                                 &iommu_debug_map_fops)) {
                pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
@@ -1989,6 +2500,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
                goto err_rmdir;
        }
 
+       if (!debugfs_create_file("dma_map", S_IWUSR, dir, ddev,
+                                        &iommu_debug_dma_map_fops)) {
+               pr_err("Couldn't create iommu/devices/%s/dma_map debugfs file\n",
+                              name);
+                       goto err_rmdir;
+       }
+
        if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
                                 &iommu_debug_unmap_fops)) {
                pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
@@ -1996,6 +2514,20 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
                goto err_rmdir;
        }
 
+       if (!debugfs_create_file("dma_unmap", S_IWUSR, dir, ddev,
+                                        &iommu_debug_dma_unmap_fops)) {
+               pr_err("Couldn't create iommu/devices/%s/dma_unmap debugfs file\n",
+                              name);
+                       goto err_rmdir;
+       }
+
+       if (!debugfs_create_file("pte", S_IWUSR, dir, ddev,
+                       &iommu_debug_pte_fops)) {
+               pr_err("Couldn't create iommu/devices/%s/pte debugfs file\n",
+                               name);
+               goto err_rmdir;
+       }
+
        if (!debugfs_create_file("config_clocks", S_IWUSR, dir, ddev,
                                 &iommu_debug_config_clocks_fops)) {
                pr_err("Couldn't create iommu/devices/%s/config_clocks debugfs file\n",
@@ -2050,6 +2582,11 @@ static int iommu_debug_init_tests(void)
                return -ENODEV;
        }
 
+       virt_addr = kzalloc(SZ_1M, GFP_KERNEL);
+
+       if (!virt_addr)
+               return -ENOMEM;
+
        return iommu_debug_populate_devices();
 }
 
index a77a450..b831796 100644 (file)
@@ -1336,6 +1336,15 @@ phys_addr_t iommu_iova_to_phys_hard(struct iommu_domain *domain,
        return domain->ops->iova_to_phys_hard(domain, iova);
 }
 
+uint64_t iommu_iova_to_pte(struct iommu_domain *domain,
+                                   dma_addr_t iova)
+{
+       if (unlikely(domain->ops->iova_to_pte == NULL))
+               return 0;
+
+       return domain->ops->iova_to_pte(domain, iova);
+}
+
 bool iommu_is_iova_coherent(struct iommu_domain *domain, dma_addr_t iova)
 {
        if (unlikely(domain->ops->is_iova_coherent == NULL))
index 15af9a9..2d203b4 100644 (file)
@@ -230,6 +230,8 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
                return -ENOMEM;
        }
 
+       raw_spin_lock_init(&cd->rlock);
+
        cd->gpc_base = of_iomap(node, 0);
        if (!cd->gpc_base) {
                pr_err("fsl-gpcv2: unable to map gpc registers\n");
index eef9097..41ba865 100644 (file)
@@ -71,10 +71,6 @@ ifeq ($(CONFIG_DM_VERITY_FEC),y)
 dm-verity-objs                 += dm-verity-fec.o
 endif
 
-ifeq ($(CONFIG_DM_ANDROID_VERITY),y)
-dm-verity-objs                 += dm-android-verity.o
-endif
-
 ifeq ($(CONFIG_DM_VERITY_AVB),y)
 dm-verity-objs                 += dm-verity-avb.o
 endif
index e9b34de..5d42d8f 100644 (file)
@@ -1481,26 +1481,29 @@ static void flush_current_bio_list(struct blk_plug_cb *cb, bool from_schedule)
        struct dm_offload *o = container_of(cb, struct dm_offload, cb);
        struct bio_list list;
        struct bio *bio;
+       int i;
 
        INIT_LIST_HEAD(&o->cb.list);
 
        if (unlikely(!current->bio_list))
                return;
 
-       list = *current->bio_list;
-       bio_list_init(current->bio_list);
-
-       while ((bio = bio_list_pop(&list))) {
-               struct bio_set *bs = bio->bi_pool;
-               if (unlikely(!bs) || bs == fs_bio_set) {
-                       bio_list_add(current->bio_list, bio);
-                       continue;
+       for (i = 0; i < 2; i++) {
+               list = current->bio_list[i];
+               bio_list_init(&current->bio_list[i]);
+
+               while ((bio = bio_list_pop(&list))) {
+                       struct bio_set *bs = bio->bi_pool;
+                       if (unlikely(!bs) || bs == fs_bio_set) {
+                               bio_list_add(&current->bio_list[i], bio);
+                               continue;
+                       }
+
+                       spin_lock(&bs->rescue_lock);
+                       bio_list_add(&bs->rescue_list, bio);
+                       queue_work(bs->rescue_workqueue, &bs->rescue_work);
+                       spin_unlock(&bs->rescue_lock);
                }
-
-               spin_lock(&bs->rescue_lock);
-               bio_list_add(&bs->rescue_list, bio);
-               queue_work(bs->rescue_workqueue, &bs->rescue_work);
-               spin_unlock(&bs->rescue_lock);
        }
 }
 
index 515554c..9be3998 100644 (file)
@@ -877,7 +877,8 @@ static sector_t wait_barrier(struct r1conf *conf, struct bio *bio)
                                     ((conf->start_next_window <
                                       conf->next_resync + RESYNC_SECTORS) &&
                                      current->bio_list &&
-                                     !bio_list_empty(current->bio_list))),
+                                    (!bio_list_empty(&current->bio_list[0]) ||
+                                     !bio_list_empty(&current->bio_list[1])))),
                                    conf->resync_lock);
                conf->nr_waiting--;
        }
index a92979e..e5ee4e9 100644 (file)
@@ -946,7 +946,8 @@ static void wait_barrier(struct r10conf *conf)
                                    !conf->barrier ||
                                    (conf->nr_pending &&
                                     current->bio_list &&
-                                    !bio_list_empty(current->bio_list)),
+                                    (!bio_list_empty(&current->bio_list[0]) ||
+                                     !bio_list_empty(&current->bio_list[1]))),
                                    conf->resync_lock);
                conf->nr_waiting--;
        }
index 2a9bb6e..c8f5c05 100644 (file)
@@ -2068,7 +2068,7 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
        spin_lock_irqsave(&tasklet->tasklet_lock, flags);
        queue_cmd = &tasklet->tasklet_queue_cmd[tasklet->taskletq_idx];
        if (queue_cmd->cmd_used) {
-               pr_err("%s: Tasklet queue overflow: %d\n",
+               pr_err_ratelimited("%s: Tasklet queue overflow: %d\n",
                        __func__, vfe_dev->pdev->id);
                spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
                return;
index caf6639..24e3223 100644 (file)
@@ -67,6 +67,10 @@ static int pix_overflow_error_count[VFE_MAX] = { 0 };
 #define CDBG(fmt, args...)
 #endif
 
+/* Backward interface compatibility for 3D THRESHOLD calculation */
+#define ISPIF_USE_DEFAULT_THRESHOLD (0)
+#define ISPIF_CALCULATE_THRESHOLD (1)
+
 static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable);
 static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
 static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd,
@@ -452,7 +456,7 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
                /* This is set when device is 8974 */
                ispif->clk_idx = 1;
        }
-
+       memset(ispif->stereo_configured, 0, sizeof(ispif->stereo_configured));
        atomic_set(&ispif->reset_trig[VFE0], 1);
        /* initiate reset of ISPIF */
        msm_camera_io_w(ISPIF_RST_CMD_MASK,
@@ -1009,21 +1013,29 @@ static int msm_ispif_config(struct ispif_device *ispif,
 }
 
 static void msm_ispif_config_stereo(struct ispif_device *ispif,
-       struct msm_ispif_param_data_ext *params) {
+       struct msm_ispif_param_data_ext *params, int use_line_width) {
 
        int i;
        enum msm_ispif_vfe_intf vfe_intf;
+       uint32_t stereo_3d_threshold = STEREO_DEFAULT_3D_THRESHOLD;
 
        for (i = 0; i < params->num; i++) {
+               vfe_intf = params->entries[i].vfe_intf;
                if (params->entries[i].intftype == PIX0 &&
-                   params->stereo_enable &&
-                   params->right_entries[i].csid < CSID_MAX) {
-                       vfe_intf = params->entries[i].vfe_intf;
+                       params->stereo_enable &&
+                       params->right_entries[i].csid < CSID_MAX &&
+                       !ispif->stereo_configured[vfe_intf]) {
                        msm_camera_io_w_mb(0x3,
                                ispif->base + ISPIF_VFE_m_OUTPUT_SEL(vfe_intf));
-                       msm_camera_io_w_mb(STEREO_DEFAULT_3D_THRESHOLD,
+                       if (use_line_width &&
+                               (params->line_width[vfe_intf] > 0))
+                               stereo_3d_threshold =
+                                       (params->line_width[vfe_intf] +
+                                                       2 * 6 - 1) / (2 * 6);
+                       msm_camera_io_w_mb(stereo_3d_threshold,
                                ispif->base +
                                        ISPIF_VFE_m_3D_THRESHOLD(vfe_intf));
+                       ispif->stereo_configured[vfe_intf] = 1;
                }
        }
 }
@@ -1132,6 +1144,8 @@ static int msm_ispif_stop_immediately(struct ispif_device *ispif,
                msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
                        cid_mask, params->entries[i].vfe_intf, 0);
                if (params->stereo_enable) {
+                       ispif->stereo_configured[
+                                       params->entries[i].vfe_intf] = 0;
                        cid_mask = msm_ispif_get_right_cids_mask_from_cfg(
                                        &params->right_entries[i],
                                        params->entries[i].num_cids);
@@ -1162,7 +1176,8 @@ static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
                rc = -EINVAL;
                return rc;
        }
-       msm_ispif_config_stereo(ispif, params);
+
+       msm_ispif_config_stereo(ispif, params, ISPIF_USE_DEFAULT_THRESHOLD);
        msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
 
        return rc;
@@ -1392,6 +1407,8 @@ static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
                if (rc < 0)
                        goto end;
                if (cid_right_mask) {
+                       ispif->stereo_configured[
+                                       params->entries[i].vfe_intf] = 0;
                        intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
                        rc = readl_poll_timeout(ispif->base + intf_addr,
                                                stop_flag,
@@ -1807,6 +1824,10 @@ static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd,
                rc = msm_ispif_config2(ispif, params);
                msm_ispif_io_dump_reg(ispif);
                break;
+       case ISPIF_CFG_STEREO:
+               msm_ispif_config_stereo(ispif, params,
+                                               ISPIF_CALCULATE_THRESHOLD);
+               break;
        default:
                pr_err("%s: invalid cfg_type\n", __func__);
                rc = -EINVAL;
index 61e8f1d..3e6680c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -77,5 +77,6 @@ struct ispif_device {
        int ispif_vdd_count;
        struct regulator *vfe_vdd[ISPIF_VFE_VDD_INFO_MAX];
        int vfe_vdd_count;
+       int stereo_configured[VFE_MAX];
 };
 #endif
index c2b42a8..f95cc37 100644 (file)
@@ -707,6 +707,9 @@ static long msm_private_ioctl(struct file *file, void *fh,
                return 0;
        }
 
+       if (!event_data)
+               return -EINVAL;
+
        memset(&event, 0, sizeof(struct v4l2_event));
        session_id = event_data->session_id;
        stream_id = event_data->stream_id;
@@ -1012,11 +1015,9 @@ static int msm_open(struct file *filep)
        BUG_ON(!pvdev);
 
        /* !!! only ONE open is allowed !!! */
-       if (atomic_read(&pvdev->opened))
+       if (atomic_cmpxchg(&pvdev->opened, 0, 1))
                return -EBUSY;
 
-       atomic_set(&pvdev->opened, 1);
-
        spin_lock_irqsave(&msm_pid_lock, flags);
        msm_pid = get_pid(task_pid(current));
        spin_unlock_irqrestore(&msm_pid_lock, flags);
index 8402e31..b7feb12 100644 (file)
@@ -2542,9 +2542,29 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
                return -EINVAL;
        }
 
-       if (stripe_base == UINT_MAX || new_frame->num_strips >
-               (UINT_MAX - 1 - stripe_base) / stripe_size) {
-               pr_err("Invalid frame message,num_strips %d is large\n",
+       /* Stripe index starts at zero */
+       if ((!new_frame->num_strips) ||
+               (new_frame->first_stripe_index >= new_frame->num_strips) ||
+               (new_frame->last_stripe_index  >= new_frame->num_strips) ||
+               (new_frame->first_stripe_index >
+                       new_frame->last_stripe_index)) {
+               pr_err("Invalid frame message, #stripes=%d, stripe indices=[%d,%d]\n",
+                       new_frame->num_strips,
+                       new_frame->first_stripe_index,
+                       new_frame->last_stripe_index);
+               return -EINVAL;
+       }
+
+       if (!stripe_size) {
+               pr_err("Invalid frame message, invalid stripe_size (%d)!\n",
+                       stripe_size);
+               return -EINVAL;
+       }
+
+       if ((stripe_base == UINT_MAX) ||
+               (new_frame->num_strips >
+                       (UINT_MAX - 1 - stripe_base) / stripe_size)) {
+               pr_err("Invalid frame message, num_strips %d is large\n",
                        new_frame->num_strips);
                return -EINVAL;
        }
@@ -2785,13 +2805,14 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev,
        struct msm_cpp_frame_info_t *frame = NULL;
        struct msm_cpp_frame_info_t k_frame_info;
        int32_t rc = 0;
-       int32_t i = 0;
-       int32_t num_buff = sizeof(k_frame_info.output_buffer_info)/
+       uint32_t i = 0;
+       uint32_t num_buff = sizeof(k_frame_info.output_buffer_info) /
                                sizeof(struct msm_cpp_buffer_info_t);
+
        if (copy_from_user(&k_frame_info,
                        (void __user *)ioctl_ptr->ioctl_ptr,
                        sizeof(k_frame_info)))
-                       return -EFAULT;
+               return -EFAULT;
 
        frame = msm_cpp_get_frame(ioctl_ptr);
        if (!frame) {
@@ -2953,8 +2974,9 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
                }
 
                *ioctl_ptr = arg;
-               if ((*ioctl_ptr == NULL) ||
-                       ((*ioctl_ptr)->ioctl_ptr == NULL)) {
+               if (((*ioctl_ptr) == NULL) ||
+                       ((*ioctl_ptr)->ioctl_ptr == NULL) ||
+                       ((*ioctl_ptr)->len == 0)) {
                        pr_err("Error invalid ioctl argument cmd %u", cmd);
                        return -EINVAL;
                }
@@ -3503,13 +3525,18 @@ STREAM_BUFF_END:
                if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
                        struct msm_camera_smmu_attach_type cpp_attach_info;
 
+                       if (ioctl_ptr->len !=
+                               sizeof(struct msm_camera_smmu_attach_type)) {
+                               rc = -EINVAL;
+                               break;
+                       }
+
                        memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
                        rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
                                ioctl_ptr);
                        if (rc < 0) {
                                pr_err("CPP_IOMMU_ATTACH copy from user fail");
-                               ERR_COPY_FROM_USER();
-                               return -EINVAL;
+                               break;
                        }
 
                        cpp_dev->security_mode = cpp_attach_info.attach;
@@ -3538,16 +3565,20 @@ STREAM_BUFF_END:
        case VIDIOC_MSM_CPP_IOMMU_DETACH: {
                if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) &&
                        (cpp_dev->stream_cnt == 0)) {
-
                        struct msm_camera_smmu_attach_type cpp_attach_info;
 
+                       if (ioctl_ptr->len !=
+                               sizeof(struct msm_camera_smmu_attach_type)) {
+                               rc = -EINVAL;
+                               break;
+                       }
+
                        memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
                        rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
                                ioctl_ptr);
                        if (rc < 0) {
                                pr_err("CPP_IOMMU_DETTACH copy from user fail");
-                               ERR_COPY_FROM_USER();
-                               return -EINVAL;
+                               break;
                        }
 
                        cpp_dev->security_mode = cpp_attach_info.attach;
@@ -3568,6 +3599,7 @@ STREAM_BUFF_END:
                } else {
                        pr_err("%s:%d IOMMMU attach triggered in invalid state\n",
                                __func__, __LINE__);
+                       rc = -EINVAL;
                }
                break;
        }
@@ -3883,6 +3915,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
        struct msm_cpp_stream_buff_info_t k_cpp_buff_info;
        struct msm_cpp_frame_info32_t k32_frame_info;
        struct msm_cpp_frame_info_t k64_frame_info;
+       struct msm_camera_smmu_attach_type kb_cpp_smmu_attach_info;
        uint32_t identity_k = 0;
        bool is_copytouser_req = true;
        void __user *up = (void __user *)arg;
@@ -4187,11 +4220,23 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
                break;
        }
        case VIDIOC_MSM_CPP_IOMMU_ATTACH32:
-               cmd = VIDIOC_MSM_CPP_IOMMU_ATTACH;
-               break;
        case VIDIOC_MSM_CPP_IOMMU_DETACH32:
-               cmd = VIDIOC_MSM_CPP_IOMMU_DETACH;
+       {
+               if ((kp_ioctl.len != sizeof(struct msm_camera_smmu_attach_type))
+                       || (copy_from_user(&kb_cpp_smmu_attach_info,
+                               (void __user *)kp_ioctl.ioctl_ptr,
+                               sizeof(kb_cpp_smmu_attach_info)))) {
+                       mutex_unlock(&cpp_dev->mutex);
+                       return -EINVAL;
+               }
+
+               kp_ioctl.ioctl_ptr = (void *)&kb_cpp_smmu_attach_info;
+               is_copytouser_req = false;
+               cmd = (cmd == VIDIOC_MSM_CPP_IOMMU_ATTACH32) ?
+                       VIDIOC_MSM_CPP_IOMMU_ATTACH :
+                       VIDIOC_MSM_CPP_IOMMU_DETACH;
                break;
+       }
        case MSM_SD_NOTIFY_FREEZE:
                break;
        case MSM_SD_UNNOTIFY_FREEZE:
@@ -4202,7 +4247,8 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
        default:
                pr_err_ratelimited("%s: unsupported compat type :%x LOAD %lu\n",
                                __func__, cmd, VIDIOC_MSM_CPP_LOAD_FIRMWARE);
-               break;
+               mutex_unlock(&cpp_dev->mutex);
+               return -EINVAL;
        }
 
        mutex_unlock(&cpp_dev->mutex);
@@ -4233,7 +4279,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
        default:
                pr_err_ratelimited("%s: unsupported compat type :%d\n",
                                __func__, cmd);
-               break;
+               return -EINVAL;
        }
 
        if (is_copytouser_req) {
index fef4a85..74f3628 100644 (file)
@@ -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
@@ -133,7 +133,7 @@ struct sde_mdp_mixer *sde_mdp_mixer_get(struct sde_mdp_ctl *ctl, int mux)
 
 int sde_mdp_get_pipe_flush_bits(struct sde_mdp_pipe *pipe)
 {
-       u32 flush_bits;
+       u32 flush_bits = 0;
 
        if (pipe->type == SDE_MDP_PIPE_TYPE_DMA)
                flush_bits |= BIT(pipe->num) << 5;
index f5df9ea..9757f35 100644 (file)
@@ -1010,8 +1010,8 @@ EXPORT_SYMBOL(dvb_usbv2_probe);
 void dvb_usbv2_disconnect(struct usb_interface *intf)
 {
        struct dvb_usb_device *d = usb_get_intfdata(intf);
-       const char *name = d->name;
-       struct device dev = d->udev->dev;
+       const char *devname = kstrdup(dev_name(&d->udev->dev), GFP_KERNEL);
+       const char *drvname = d->name;
 
        dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
                        intf->cur_altsetting->desc.bInterfaceNumber);
@@ -1021,8 +1021,9 @@ void dvb_usbv2_disconnect(struct usb_interface *intf)
 
        dvb_usbv2_exit(d);
 
-       dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
-                       KBUILD_MODNAME, name);
+       pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
+               KBUILD_MODNAME, drvname, devname);
+       kfree(devname);
 }
 EXPORT_SYMBOL(dvb_usbv2_disconnect);
 
index 733a7ff..caad3b5 100644 (file)
@@ -35,42 +35,51 @@ static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 le
 
 int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
-       struct hexline hx;
-       u8 reset;
-       int ret,pos=0;
+       struct hexline *hx;
+       u8 *buf;
+       int ret, pos = 0;
+       u16 cpu_cs_register = cypress[type].cpu_cs_register;
+
+       buf = kmalloc(sizeof(*hx), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       hx = (struct hexline *)buf;
 
        /* stop the CPU */
-       reset = 1;
-       if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+       buf[0] = 1;
+       if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
                err("could not stop the USB controller CPU.");
 
-       while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
-               deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
-               ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+       while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
+               deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
+               ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
 
-               if (ret != hx.len) {
+               if (ret != hx->len) {
                        err("error while transferring firmware "
                                "(transferred size: %d, block size: %d)",
-                               ret,hx.len);
+                               ret, hx->len);
                        ret = -EINVAL;
                        break;
                }
        }
        if (ret < 0) {
                err("firmware download failed at %d with %d",pos,ret);
+               kfree(buf);
                return ret;
        }
 
        if (ret == 0) {
                /* restart the CPU */
-               reset = 0;
-               if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+               buf[0] = 0;
+               if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
                        err("could not restart the USB controller CPU.");
                        ret = -EINVAL;
                }
        } else
                ret = -EIO;
 
+       kfree(buf);
+
        return ret;
 }
 EXPORT_SYMBOL(usb_cypress_load_firmware);
index 8476174..e602650 100644 (file)
@@ -17,7 +17,6 @@
 #include "q6audio_common.h"
 #include "audio_utils_aio.h"
 #include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
 
 #define MAX_CHANNELS_SUPPORTED         8
 #define WAIT_TIMEDOUT_DURATION_SECS    1
@@ -53,31 +52,11 @@ static void audio_effects_init_pp(struct audio_client *ac)
                pr_err("%s: audio client null to init pp\n", __func__);
                return;
        }
-       switch (ac->topology) {
-       case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-
-               ret = q6asm_set_softvolume_v2(ac, &softvol,
-                                             SOFT_VOLUME_INSTANCE_1);
-               if (ret < 0)
-                       pr_err("%s: Send SoftVolume1 Param failed ret=%d\n",
-                               __func__, ret);
-               ret = q6asm_set_softvolume_v2(ac, &softvol,
-                                             SOFT_VOLUME_INSTANCE_2);
-               if (ret < 0)
-                       pr_err("%s: Send SoftVolume2 Param failed ret=%d\n",
-                                __func__, ret);
-
-               msm_dts_eagle_init_master_module(ac);
-
-               break;
-       default:
-               ret = q6asm_set_softvolume_v2(ac, &softvol,
-                                             SOFT_VOLUME_INSTANCE_1);
-               if (ret < 0)
-                       pr_err("%s: Send SoftVolume Param failed ret=%d\n",
-                               __func__, ret);
-               break;
-       }
+       ret = q6asm_set_softvolume_v2(ac, &softvol,
+                                     SOFT_VOLUME_INSTANCE_1);
+       if (ret < 0)
+               pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+                       __func__, ret);
 }
 
 static void audio_effects_deinit_pp(struct audio_client *ac)
@@ -86,13 +65,6 @@ static void audio_effects_deinit_pp(struct audio_client *ac)
                pr_err("%s: audio client null to deinit pp\n", __func__);
                return;
        }
-       switch (ac->topology) {
-       case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-               msm_dts_eagle_deinit_master_module(ac);
-               break;
-       default:
-               break;
-       }
 }
 
 static void audio_effects_event_handler(uint32_t opcode, uint32_t token,
@@ -428,33 +400,6 @@ static long audio_effects_set_pp_param(struct q6audio_effects *effects,
                              &(effects->audio_effects.topo_switch_vol),
                              (long *)&values[1], SOFT_VOLUME_INSTANCE_2);
                break;
-       case DTS_EAGLE_MODULE_ENABLE:
-               pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__);
-               if (msm_audio_effects_is_effmodule_supp_in_top(
-                       effects_module, effects->ac->topology)) {
-                       /*
-                        * HPX->OFF: first disable HPX and then
-                        * enable SA+
-                        * HPX->ON: first disable SA+ and then
-                        * enable HPX
-                        */
-                       bool hpx_state = (bool)values[1];
-                       if (hpx_state)
-                               msm_audio_effects_enable_extn(effects->ac,
-                                       &(effects->audio_effects),
-                                       false);
-                       msm_dts_eagle_enable_asm(effects->ac,
-                               hpx_state,
-                               AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-                       msm_dts_eagle_enable_asm(effects->ac,
-                               hpx_state,
-                               AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
-                       if (!hpx_state)
-                               msm_audio_effects_enable_extn(effects->ac,
-                                       &(effects->audio_effects),
-                                       true);
-               }
-               break;
        default:
                pr_err("%s: Invalid effects config module\n", __func__);
                rc = -EINVAL;
index b7af808..e3f23ca 100644 (file)
@@ -851,6 +851,7 @@ static long audio_aio_process_event_req_compat(struct q6audio_aio *audio,
        long rc;
        struct msm_audio_event32 usr_evt_32;
        struct msm_audio_event usr_evt;
+       memset(&usr_evt, 0, sizeof(struct msm_audio_event));
 
        if (copy_from_user(&usr_evt_32, arg,
                                sizeof(struct msm_audio_event32))) {
@@ -860,6 +861,11 @@ static long audio_aio_process_event_req_compat(struct q6audio_aio *audio,
        usr_evt.timeout_ms = usr_evt_32.timeout_ms;
 
        rc = audio_aio_process_event_req_common(audio, &usr_evt);
+       if (rc < 0) {
+               pr_err("%s: audio process event failed, rc = %ld",
+                       __func__, rc);
+               return rc;
+       }
 
        usr_evt_32.event_type = usr_evt.event_type;
        switch (usr_evt_32.event_type) {
index 204b234..ad21276 100644 (file)
@@ -95,9 +95,11 @@ static int uid_cputime_show(struct seq_file *m, void *v)
 {
        struct uid_entry *uid_entry;
        struct task_struct *task, *temp;
+       struct user_namespace *user_ns = current_user_ns();
        cputime_t utime;
        cputime_t stime;
        unsigned long bkt;
+       uid_t uid;
 
        rt_mutex_lock(&uid_lock);
 
@@ -108,14 +110,13 @@ static int uid_cputime_show(struct seq_file *m, void *v)
 
        read_lock(&tasklist_lock);
        do_each_thread(temp, task) {
-               uid_entry = find_or_register_uid(from_kuid_munged(
-                       current_user_ns(), task_uid(task)));
+               uid = from_kuid_munged(user_ns, task_uid(task));
+               uid_entry = find_or_register_uid(uid);
                if (!uid_entry) {
                        read_unlock(&tasklist_lock);
                        rt_mutex_unlock(&uid_lock);
                        pr_err("%s: failed to find the uid_entry for uid %d\n",
-                               __func__, from_kuid_munged(current_user_ns(),
-                               task_uid(task)));
+                               __func__, uid);
                        return -ENOMEM;
                }
                task_cputime_adjusted(task, &utime, &stime);
@@ -237,28 +238,28 @@ static void clean_uid_io_last_stats(struct uid_entry *uid_entry,
        io_last->fsync -= task->ioac.syscfs;
 }
 
-static void update_io_stats_locked(void)
+static void update_io_stats_all_locked(void)
 {
        struct uid_entry *uid_entry;
        struct task_struct *task, *temp;
        struct io_stats *io_bucket, *io_curr, *io_last;
+       struct user_namespace *user_ns = current_user_ns();
        unsigned long bkt;
-
-       BUG_ON(!rt_mutex_is_locked(&uid_lock));
+       uid_t uid;
 
        hash_for_each(hash_table, bkt, uid_entry, hash)
                memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
                        sizeof(struct io_stats));
 
-       read_lock(&tasklist_lock);
+       rcu_read_lock();
        do_each_thread(temp, task) {
-               uid_entry = find_or_register_uid(from_kuid_munged(
-                       current_user_ns(), task_uid(task)));
+               uid = from_kuid_munged(user_ns, task_uid(task));
+               uid_entry = find_or_register_uid(uid);
                if (!uid_entry)
                        continue;
                add_uid_io_curr_stats(uid_entry, task);
        } while_each_thread(temp, task);
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        hash_for_each(hash_table, bkt, uid_entry, hash) {
                io_bucket = &uid_entry->io[uid_entry->state];
@@ -281,6 +282,47 @@ static void update_io_stats_locked(void)
        }
 }
 
+static void update_io_stats_uid_locked(uid_t target_uid)
+{
+       struct uid_entry *uid_entry;
+       struct task_struct *task, *temp;
+       struct io_stats *io_bucket, *io_curr, *io_last;
+       struct user_namespace *user_ns = current_user_ns();
+
+       uid_entry = find_or_register_uid(target_uid);
+       if (!uid_entry)
+               return;
+
+       memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
+               sizeof(struct io_stats));
+
+       rcu_read_lock();
+       do_each_thread(temp, task) {
+               if (from_kuid_munged(user_ns, task_uid(task)) != target_uid)
+                       continue;
+               add_uid_io_curr_stats(uid_entry, task);
+       } while_each_thread(temp, task);
+       rcu_read_unlock();
+
+       io_bucket = &uid_entry->io[uid_entry->state];
+       io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR];
+       io_last = &uid_entry->io[UID_STATE_TOTAL_LAST];
+
+       io_bucket->read_bytes +=
+               io_curr->read_bytes - io_last->read_bytes;
+       io_bucket->write_bytes +=
+               io_curr->write_bytes - io_last->write_bytes;
+       io_bucket->rchar += io_curr->rchar - io_last->rchar;
+       io_bucket->wchar += io_curr->wchar - io_last->wchar;
+       io_bucket->fsync += io_curr->fsync - io_last->fsync;
+
+       io_last->read_bytes = io_curr->read_bytes;
+       io_last->write_bytes = io_curr->write_bytes;
+       io_last->rchar = io_curr->rchar;
+       io_last->wchar = io_curr->wchar;
+       io_last->fsync = io_curr->fsync;
+}
+
 static int uid_io_show(struct seq_file *m, void *v)
 {
        struct uid_entry *uid_entry;
@@ -288,7 +330,7 @@ static int uid_io_show(struct seq_file *m, void *v)
 
        rt_mutex_lock(&uid_lock);
 
-       update_io_stats_locked();
+       update_io_stats_all_locked();
 
        hash_for_each(hash_table, bkt, uid_entry, hash) {
                seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
@@ -363,7 +405,7 @@ static ssize_t uid_procstat_write(struct file *file,
                return count;
        }
 
-       update_io_stats_locked();
+       update_io_stats_uid_locked(uid);
 
        uid_entry->state = state;
 
@@ -401,7 +443,7 @@ static int process_notifier(struct notifier_block *self,
        uid_entry->utime += utime;
        uid_entry->stime += stime;
 
-       update_io_stats_locked();
+       update_io_stats_uid_locked(uid);
        clean_uid_io_last_stats(uid_entry, task);
 
 exit:
index f5dbb67..ccf22eb 100644 (file)
@@ -128,14 +128,11 @@ static int mmc_cmdq_thread(void *d)
 
                ret = mq->cmdq_issue_fn(mq, mq->cmdq_req_peeked);
                /*
-                * Don't requeue if issue_fn fails, just bug on.
-                * We don't expect failure here and there is no recovery other
-                * than fixing the actual issue if there is any.
+                * Don't requeue if issue_fn fails.
+                * Recovery will be come by completion softirq
                 * Also we end the request if there is a partition switch error,
                 * so we should not requeue the request here.
                 */
-               if (ret)
-                       BUG_ON(1);
        } /* loop */
 
        return 0;
index 41f0935..c462eee 100644 (file)
@@ -3944,12 +3944,10 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)
  */
 int mmc_cmdq_hw_reset(struct mmc_host *host)
 {
-       if (!host->bus_ops->power_restore)
-       return -EOPNOTSUPP;
+       if (!host->bus_ops->reset)
+               return -EOPNOTSUPP;
 
-       mmc_power_cycle(host, host->ocr_avail);
-       mmc_select_voltage(host, host->card->ocr);
-       return host->bus_ops->power_restore(host);
+       return host->bus_ops->reset(host);
 }
 EXPORT_SYMBOL(mmc_cmdq_hw_reset);
 
@@ -3969,8 +3967,9 @@ int mmc_hw_reset(struct mmc_host *host)
        ret = host->bus_ops->reset(host);
        mmc_bus_put(host);
 
-       if (ret != -EOPNOTSUPP)
-               pr_warn("%s: tried to reset card\n", mmc_hostname(host));
+       if (ret)
+               pr_warn("%s: tried to reset card, got error %d\n",
+                       mmc_hostname(host), ret);
 
        return ret;
 }
index e829450..9ca73a2 100644 (file)
@@ -653,19 +653,19 @@ static ssize_t store_enable(struct device *dev,
        mmc_get_card(host->card);
 
        if (!value) {
-               /*turning off clock scaling*/
-               mmc_exit_clk_scaling(host);
+               /* Suspend the clock scaling and mask host capability */
+               if (host->clk_scaling.enable)
+                       mmc_suspend_clk_scaling(host);
                host->caps2 &= ~MMC_CAP2_CLK_SCALE;
                host->clk_scaling.state = MMC_LOAD_HIGH;
                /* Set to max. frequency when disabling */
                mmc_clk_update_freq(host, host->card->clk_scaling_highest,
                                        host->clk_scaling.state);
        } else if (value) {
-               /* starting clock scaling, will restart in case started */
+               /* Unmask host capability and resume scaling */
                host->caps2 |= MMC_CAP2_CLK_SCALE;
-               if (host->clk_scaling.enable)
-                       mmc_exit_clk_scaling(host);
-               mmc_init_clk_scaling(host);
+               if (!host->clk_scaling.enable)
+                       mmc_resume_clk_scaling(host);
        }
 
        mmc_put_card(host->card);
index afdf700..6912871 100644 (file)
@@ -2892,23 +2892,42 @@ EXPORT_SYMBOL(mmc_can_reset);
 static int mmc_reset(struct mmc_host *host)
 {
        struct mmc_card *card = host->card;
+       int ret;
+
+       if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
+            mmc_can_reset(card)) {
+               /* If the card accept RST_n signal, send it. */
+               mmc_set_clock(host, host->f_init);
+               host->ops->hw_reset(host);
+               /* Set initial state and call mmc_set_ios */
+               mmc_set_initial_state(host);
+       } else {
+               /* Do a brute force power cycle */
+               mmc_power_cycle(host, card->ocr);
+       }
 
-       if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
-               return -EOPNOTSUPP;
-
-       if (!mmc_can_reset(card))
-               return -EOPNOTSUPP;
+       /* Suspend clk scaling to avoid switching frequencies intermittently */
 
-       mmc_host_clk_hold(host);
-       mmc_set_clock(host, host->f_init);
+       ret = mmc_suspend_clk_scaling(host);
+       if (ret) {
+               pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
+                       mmc_hostname(host), __func__, ret);
+               return ret;
+       }
 
-       host->ops->hw_reset(host);
+       ret = mmc_init_card(host, host->card->ocr, host->card);
+       if (ret) {
+               pr_err("%s: %s: mmc_init_card failed (%d)\n",
+                       mmc_hostname(host), __func__, ret);
+               return ret;
+       }
 
-       /* Set initial state and call mmc_set_ios */
-       mmc_set_initial_state(host);
-       mmc_host_clk_release(host);
+       ret = mmc_resume_clk_scaling(host);
+       if (ret)
+               pr_err("%s: %s: fail to resume clock scaling (%d)\n",
+                       mmc_hostname(host), __func__, ret);
 
-       return mmc_init_card(host, card->ocr, card);
+       return ret;
 }
 
 static const struct mmc_bus_ops mmc_ops = {
index a83960f..3f741f8 100644 (file)
@@ -1102,12 +1102,17 @@ skip_cqterri:
                 * before setting doorbell, hence one is not needed here.
                 */
                for_each_set_bit(tag, &comp_status, cq_host->num_slots) {
-                       /* complete the corresponding mrq */
-                       pr_debug("%s: completing tag -> %lu\n",
-                                mmc_hostname(mmc), tag);
-                       MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
-                               __func__, tag);
+                       mrq = get_req_by_tag(cq_host, tag);
+                       if (!((mrq->cmd && mrq->cmd->error) ||
+                                       mrq->cmdq_req->resp_err ||
+                                       (mrq->data && mrq->data->error))) {
+                               /* complete the corresponding mrq */
+                               pr_debug("%s: completing tag -> %lu\n",
+                                        mmc_hostname(mmc), tag);
+                               MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
+                                       __func__, tag);
                                cmdq_finish_data(mmc, tag);
+                       }
                }
        }
 
index 1f1582f..8d83877 100644 (file)
@@ -804,6 +804,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
 
        switch (uhs) {
        case MMC_TIMING_UHS_SDR50:
+       case MMC_TIMING_UHS_DDR50:
                pinctrl = imx_data->pins_100mhz;
                break;
        case MMC_TIMING_UHS_SDR104:
index c0720c1..5abab88 100644 (file)
@@ -225,12 +225,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
 
                        last_trx_part = curr_part - 1;
 
-                       /*
-                        * We have whole TRX scanned, skip to the next part. Use
-                        * roundown (not roundup), as the loop will increase
-                        * offset in next step.
-                        */
-                       offset = rounddown(offset + trx->length, blocksize);
+                       /* Jump to the end of TRX */
+                       offset = roundup(offset + trx->length, blocksize);
+                       /* Next loop iteration will increase the offset */
+                       offset -= blocksize;
                        continue;
                }
 
index 0134ba3..3971256 100644 (file)
@@ -148,11 +148,11 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
                        return err;
        }
 
-       if (bytes == 0) {
-               err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
-               if (err)
-                       return err;
+       err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
+       if (err)
+               return err;
 
+       if (bytes == 0) {
                err = clear_update_marker(ubi, vol, 0);
                if (err)
                        return err;
index c7a2182..a93f979 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 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
@@ -18,6 +18,7 @@
 #include <linux/spi/spi.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
+#include <linux/completion.h>
 
 #define DEBUG_RH850    0
 #if DEBUG_RH850 == 1
 #define MAX_TX_BUFFERS         1
 #define XFER_BUFFER_SIZE       64
 #define RX_ASSEMBLY_BUFFER_SIZE        128
-#define RH850_CLOCK    80000000
+#define RH850_CLOCK    16000000
 #define RH850_MAX_CHANNELS     4
+#define DRIVER_MODE_RAW_FRAMES 0
+#define DRIVER_MODE_PROPERTIES 1
+#define DRIVER_MODE_AMB 2
 
 struct rh850_can {
        struct net_device       *netdev[RH850_MAX_CHANNELS];
@@ -50,6 +54,10 @@ struct rh850_can {
        char *assembly_buffer;
        u8 assembly_buffer_size;
        atomic_t netif_queue_stop;
+       struct completion response_completion;
+       int wait_cmd;
+       int cmd_result;
+       int driver_mode;
 };
 
 struct rh850_netdev_privdata {
@@ -84,6 +92,36 @@ struct spi_miso { /* TLV for MISO line */
 #define CMD_CAN_ADD_FILTER     0x83
 #define CMD_CAN_REMOVE_FILTER  0x84
 #define CMD_CAN_RECEIVE_FRAME  0x85
+#define CMD_CAN_CONFIG_BIT_TIMING      0x86
+
+#define CMD_CAN_DATA_BUFF_ADD  0x87
+#define CMD_CAN_DATA_BUFF_REMOVE       0X88
+#define CMD_CAN_RELEASE_BUFFER 0x89
+#define CMD_CAN_DATA_BUFF_REMOVE_ALL   0x8A
+#define CMD_PROPERTY_WRITE     0x8B
+#define CMD_PROPERTY_READ      0x8C
+
+#define CMD_GET_FW_BR_VERSION          0x95
+#define CMD_BEGIN_FIRMWARE_UPGRADE     0x96
+#define CMD_FIRMWARE_UPGRADE_DATA      0x97
+#define CMD_END_FIRMWARE_UPGRADE       0x98
+#define CMD_BEGIN_BOOT_ROM_UPGRADE     0x99
+#define CMD_BOOT_ROM_UPGRADE_DATA      0x9A
+#define CMD_END_BOOT_ROM_UPGRADE       0x9B
+
+#define IOCTL_RELEASE_CAN_BUFFER       (SIOCDEVPRIVATE + 0)
+#define IOCTL_ENABLE_BUFFERING         (SIOCDEVPRIVATE + 1)
+#define IOCTL_ADD_FRAME_FILTER         (SIOCDEVPRIVATE + 2)
+#define IOCTL_REMOVE_FRAME_FILTER      (SIOCDEVPRIVATE + 3)
+#define IOCTL_DISABLE_BUFFERING                (SIOCDEVPRIVATE + 5)
+#define IOCTL_DISABLE_ALL_BUFFERING    (SIOCDEVPRIVATE + 6)
+#define IOCTL_GET_FW_BR_VERSION                (SIOCDEVPRIVATE + 7)
+#define IOCTL_BEGIN_FIRMWARE_UPGRADE   (SIOCDEVPRIVATE + 8)
+#define IOCTL_FIRMWARE_UPGRADE_DATA    (SIOCDEVPRIVATE + 9)
+#define IOCTL_END_FIRMWARE_UPGRADE     (SIOCDEVPRIVATE + 10)
+#define IOCTL_BEGIN_BOOT_ROM_UPGRADE   (SIOCDEVPRIVATE + 11)
+#define IOCTL_BOOT_ROM_UPGRADE_DATA    (SIOCDEVPRIVATE + 12)
+#define IOCTL_END_BOOT_ROM_UPGRADE     (SIOCDEVPRIVATE + 13)
 
 struct can_fw_resp {
        u8 maj;
@@ -126,15 +164,82 @@ struct can_receive_frame {
        u8 data[];
 } __packed;
 
+struct can_config_bit_timing {
+       u8 can_if;
+       u32 brp;
+       u32 tseg1;
+       u32 tseg2;
+       u32 sjw;
+} __packed;
+
+struct vehicle_property {
+       int id;
+       u64 ts;
+       int zone;
+       int val_type;
+       u32 data_len;
+       union {
+               u8 bval;
+               int val;
+               int val_arr[4];
+               float f_value;
+               float float_arr[4];
+               u8 str[36];
+       };
+} __packed;
+
+/* IOCTL messages */
+struct rh850_release_can_buffer {
+       u8 enable;
+} __packed;
+
+struct rh850_add_can_buffer {
+       u8 can_if;
+       u32 mid;
+       u32 mask;
+} __packed;
+
+struct rh850_delete_can_buffer {
+       u8 can_if;
+       u32 mid;
+       u32 mask;
+} __packed;
+
+struct can_fw_br_resp {
+       u8 maj;
+       u8 min;
+       u8 ver[32];
+       u8 br_maj;
+       u8 br_min;
+       u8 curr_exec_mode;
+} __packed;
+
+struct rh850_ioctl_req {
+       u8 len;
+       u8 data[];
+} __packed;
+
 static struct can_bittiming_const rh850_bittiming_const = {
        .name = "rh850",
-       .tseg1_min = 4,
+       .tseg1_min = 1,
        .tseg1_max = 16,
-       .tseg2_min = 2,
-       .tseg2_max = 8,
+       .tseg2_min = 1,
+       .tseg2_max = 16,
        .sjw_max = 4,
-       .brp_min = 4,
-       .brp_max = 1023,
+       .brp_min = 1,
+       .brp_max = 70,
+       .brp_inc = 1,
+};
+
+static struct can_bittiming_const rh850_data_bittiming_const = {
+       .name = "rh850",
+       .tseg1_min = 1,
+       .tseg1_max = 16,
+       .tseg2_min = 1,
+       .tseg2_max = 16,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 70,
        .brp_inc = 1,
 };
 
@@ -165,7 +270,7 @@ static void rh850_receive_frame(struct rh850_can *priv_data,
        }
        netdev = priv_data->netdev[frame->can_if];
        skb = alloc_can_skb(netdev, &cf);
-       if (skb == NULL) {
+       if (!skb) {
                LOGDE("skb alloc failed. frame->can_if %d\n", frame->can_if);
                return;
        }
@@ -191,9 +296,51 @@ static void rh850_receive_frame(struct rh850_can *priv_data,
        netdev->stats.rx_packets++;
 }
 
-static void rh850_process_response(struct rh850_can *priv_data,
-                                  struct spi_miso *resp, int length)
+static void rh850_receive_property(struct rh850_can *priv_data,
+                                  struct vehicle_property *property)
 {
+       struct canfd_frame *cfd;
+       u8 *p;
+       struct sk_buff *skb;
+       struct skb_shared_hwtstamps *skt;
+       struct timeval tv;
+       static u64 nanosec;
+       struct net_device *netdev;
+       int i;
+
+       /* can0 as the channel with properties */
+       netdev = priv_data->netdev[0];
+       skb = alloc_canfd_skb(netdev, &cfd);
+       if (!skb) {
+               LOGDE("skb alloc failed. frame->can_if %d\n", 0);
+               return;
+       }
+
+       LOGDI("rcv property:0x%x data:%2x %2x %2x %2x",
+             property->id, property->str[0], property->str[1],
+             property->str[2], property->str[3]);
+       cfd->can_id = 0x00;
+       cfd->len = sizeof(struct vehicle_property);
+
+       p = (u8 *)property;
+       for (i = 0; i < cfd->len; i++)
+               cfd->data[i] = p[i];
+
+       nanosec = le64_to_cpu(property->ts);
+       tv.tv_sec = (int)(nanosec / 1000000000);
+       tv.tv_usec = (int)(nanosec - (u64)tv.tv_sec * 1000000000) / 1000;
+       skt = skb_hwtstamps(skb);
+       skt->hwtstamp = timeval_to_ktime(tv);
+       LOGDI("  hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp));
+       skb->tstamp = timeval_to_ktime(tv);
+       netif_rx(skb);
+       netdev->stats.rx_packets++;
+}
+
+static int rh850_process_response(struct rh850_can *priv_data,
+                                 struct spi_miso *resp, int length)
+{
+       int ret = 0;
        LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq);
        if (resp->cmd == CMD_CAN_RECEIVE_FRAME) {
                struct can_receive_frame *frame =
@@ -208,19 +355,55 @@ static void rh850_process_response(struct rh850_can *priv_data,
                } else {
                        rh850_receive_frame(priv_data, frame);
                }
+       } else if (resp->cmd == CMD_PROPERTY_READ) {
+               struct vehicle_property *property =
+                               (struct vehicle_property *)&resp->data;
+               if (resp->len > length) {
+                       LOGDE("Error. This should never happen\n");
+                       LOGDE("process_response: Saving %d bytes\n",
+                             length);
+                       memcpy(priv_data->assembly_buffer, (char *)resp,
+                              length);
+                       priv_data->assembly_buffer_size = length;
+               } else {
+                       rh850_receive_property(priv_data, property);
+               }
        } else if (resp->cmd  == CMD_GET_FW_VERSION) {
                struct can_fw_resp *fw_resp = (struct can_fw_resp *)resp->data;
                dev_info(&priv_data->spidev->dev, "fw %d.%d",
                         fw_resp->maj, fw_resp->min);
                dev_info(&priv_data->spidev->dev, "fw string %s",
                         fw_resp->ver);
+       } else if (resp->cmd  == CMD_GET_FW_BR_VERSION) {
+               struct can_fw_br_resp *fw_resp =
+                               (struct can_fw_br_resp *)resp->data;
+
+               dev_info(&priv_data->spidev->dev, "fw_can %d.%d",
+                        fw_resp->maj, fw_resp->min);
+               dev_info(&priv_data->spidev->dev, "fw string %s",
+                        fw_resp->ver);
+               dev_info(&priv_data->spidev->dev, "fw_br %d.%d exec_mode %d",
+                        fw_resp->br_maj, fw_resp->br_min,
+                        fw_resp->curr_exec_mode);
+               ret = fw_resp->curr_exec_mode << 28;
+               ret |= (fw_resp->br_maj & 0xF) << 24;
+               ret |= (fw_resp->br_min & 0xFF) << 16;
+               ret |= (fw_resp->maj & 0xF) << 8;
+               ret |= (fw_resp->min & 0xFF);
+       }
+
+       if (resp->cmd == priv_data->wait_cmd) {
+               priv_data->cmd_result = ret;
+               complete(&priv_data->response_completion);
        }
+       return ret;
 }
 
-static void rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
+static int rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
 {
        struct spi_miso *resp;
        int length_processed = 0, actual_length = priv_data->xfer_length;
+       int ret = 0;
 
        while (length_processed < actual_length) {
                int length_left = actual_length - length_processed;
@@ -237,7 +420,8 @@ static void rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
                               rx_buf, 2);
                        data = priv_data->assembly_buffer;
                        resp = (struct spi_miso *)data;
-                       length = resp->len - priv_data->assembly_buffer_size;
+                       length = resp->len + sizeof(*resp)
+                                       - priv_data->assembly_buffer_size;
                        if (length > 0)
                                memcpy(priv_data->assembly_buffer +
                                       priv_data->assembly_buffer_size,
@@ -258,15 +442,11 @@ static void rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
                      length_processed, length_left, priv_data->xfer_length);
                length_processed += length;
                if (length_left >= sizeof(*resp) &&
-                   resp->len <= length_left) {
+                   resp->len + sizeof(*resp) <= length_left) {
                        struct spi_miso *resp =
                                        (struct spi_miso *)data;
-                       if (resp->len < sizeof(struct spi_miso)) {
-                               LOGDE("Error resp->len is %d). Abort.\n",
-                                     resp->len);
-                               break;
-                       }
-                       rh850_process_response(priv_data, resp, length_left);
+                       ret = rh850_process_response(priv_data, resp,
+                                                    length_left);
                } else if (length_left > 0) {
                        /* Not full message. Store however much we have for */
                        /* later assembly */
@@ -277,6 +457,7 @@ static void rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
                        break;
                }
        }
+       return ret;
 }
 
 static int rh850_do_spi_transaction(struct rh850_can *priv_data)
@@ -291,15 +472,20 @@ static int rh850_do_spi_transaction(struct rh850_can *priv_data)
        msg = kzalloc(sizeof(*msg), GFP_KERNEL);
        if (xfer == 0 || msg == 0)
                return -ENOMEM;
+       LOGDI(">%x %2d [%d]\n", priv_data->tx_buf[0],
+             priv_data->tx_buf[1], priv_data->tx_buf[2]);
        spi_message_init(msg);
        spi_message_add_tail(xfer, msg);
        xfer->tx_buf = priv_data->tx_buf;
        xfer->rx_buf = priv_data->rx_buf;
        xfer->len = priv_data->xfer_length;
        ret = spi_sync(spi, msg);
-       LOGDI("spi_sync ret %d\n", ret);
+       LOGDI("spi_sync ret %d data %x %x %x %x %x %x %x %x\n", ret,
+             priv_data->rx_buf[0], priv_data->rx_buf[1], priv_data->rx_buf[2],
+             priv_data->rx_buf[3], priv_data->rx_buf[4], priv_data->rx_buf[5],
+             priv_data->rx_buf[6], priv_data->rx_buf[7]);
        if (ret == 0)
-               rh850_process_rx(priv_data, priv_data->rx_buf);
+               ret = rh850_process_rx(priv_data, priv_data->rx_buf);
        kfree(msg);
        kfree(xfer);
        return ret;
@@ -347,8 +533,54 @@ static int rh850_query_firmware_version(struct rh850_can *priv_data)
        return ret;
 }
 
+static int rh850_set_bitrate(struct net_device *netdev)
+{
+       char *tx_buf, *rx_buf;
+       int ret;
+       struct spi_mosi *req;
+       struct can_config_bit_timing *req_d;
+       struct rh850_can *priv_data;
+       struct can_priv *priv = netdev_priv(netdev);
+       struct rh850_netdev_privdata *rh850_priv;
+
+       rh850_priv = netdev_priv(netdev);
+       priv_data = rh850_priv->rh850_can;
+
+       netdev_info(netdev, "ch%i,  bitrate setting>%i",
+                   rh850_priv->netdev_index, priv->bittiming.bitrate);
+       LOGNI("sjw>%i brp>%i ph_sg1>%i ph_sg2>%i smpl_pt>%i tq>%i pr_seg>%i",
+             priv->bittiming.sjw, priv->bittiming.brp,
+             priv->bittiming.phase_seg1,
+             priv->bittiming.phase_seg2,
+             priv->bittiming.sample_point,
+             priv->bittiming.tq, priv->bittiming.prop_seg);
+
+       mutex_lock(&priv_data->spi_lock);
+       tx_buf = priv_data->tx_buf;
+       rx_buf = priv_data->rx_buf;
+       memset(tx_buf, 0, XFER_BUFFER_SIZE);
+       memset(rx_buf, 0, XFER_BUFFER_SIZE);
+       priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+       req = (struct spi_mosi *)tx_buf;
+       req->cmd = CMD_CAN_CONFIG_BIT_TIMING;
+       req->len = sizeof(struct can_config_bit_timing);
+       req->seq = atomic_inc_return(&priv_data->msg_seq);
+       req_d = (struct can_config_bit_timing *)req->data;
+       req_d->can_if = rh850_priv->netdev_index;
+       req_d->brp = priv->bittiming.brp;
+       req_d->tseg1 = priv->bittiming.phase_seg1 + priv->bittiming.prop_seg;
+       req_d->tseg2 = priv->bittiming.phase_seg2;
+       req_d->sjw = priv->bittiming.sjw;
+
+       ret = rh850_do_spi_transaction(priv_data);
+       mutex_unlock(&priv_data->spi_lock);
+
+       return ret;
+}
+
 static int rh850_can_write(struct rh850_can *priv_data,
-                          int can_channel, struct can_frame *cf)
+                          int can_channel, struct canfd_frame *cf)
 {
        char *tx_buf, *rx_buf;
        int ret, i;
@@ -369,16 +601,29 @@ static int rh850_can_write(struct rh850_can *priv_data,
        priv_data->xfer_length = XFER_BUFFER_SIZE;
 
        req = (struct spi_mosi *)tx_buf;
-       req->cmd = CMD_CAN_SEND_FRAME;
-       req->len = sizeof(struct can_write_req) + 8;
-       req->seq = atomic_inc_return(&priv_data->msg_seq);
-
-       req_d = (struct can_write_req *)req->data;
-       req_d->can_if = can_channel;
-       req_d->mid = cf->can_id;
-       req_d->dlc = cf->can_dlc;
-       for (i = 0; i < cf->can_dlc; i++)
-               req_d->data[i] = cf->data[i];
+       if (priv_data->driver_mode == DRIVER_MODE_RAW_FRAMES) {
+               req->cmd = CMD_CAN_SEND_FRAME;
+               req->len = sizeof(struct can_write_req) + 8;
+               req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+               req_d = (struct can_write_req *)req->data;
+               req_d->can_if = can_channel;
+               req_d->mid = cf->can_id;
+               req_d->dlc = cf->len;
+
+               for (i = 0; i < cf->len; i++)
+                       req_d->data[i] = cf->data[i];
+       } else if (priv_data->driver_mode == DRIVER_MODE_PROPERTIES ||
+                  priv_data->driver_mode == DRIVER_MODE_AMB) {
+               req->cmd = CMD_PROPERTY_WRITE;
+               req->len = sizeof(struct vehicle_property);
+               req->seq = atomic_inc_return(&priv_data->msg_seq);
+               for (i = 0; i < cf->len; i++)
+                       req->data[i] = cf->data[i];
+       } else {
+               LOGDE("rh850_can_write: wrong driver mode %i",
+                     priv_data->driver_mode);
+       }
 
        ret = rh850_do_spi_transaction(priv_data);
        netdev = priv_data->netdev[can_channel];
@@ -414,7 +659,7 @@ static int rh850_netdev_close(struct net_device *netdev)
 static void rh850_send_can_frame(struct work_struct *ws)
 {
        struct rh850_tx_work *tx_work;
-       struct can_frame *cf;
+       struct canfd_frame *cf;
        struct rh850_can *priv_data;
        struct net_device *netdev;
        struct rh850_netdev_privdata *netdev_priv_data;
@@ -428,7 +673,7 @@ static void rh850_send_can_frame(struct work_struct *ws)
        LOGDI("send_can_frame ws %p\n", ws);
        LOGDI("send_can_frame tx %p\n", tx_work);
 
-       cf = (struct can_frame *)tx_work->skb->data;
+       cf = (struct canfd_frame *)tx_work->skb->data;
        rh850_can_write(priv_data, can_channel, cf);
 
        dev_kfree_skb(tx_work->skb);
@@ -458,10 +703,304 @@ static netdev_tx_t rh850_netdev_start_xmit(
        return NETDEV_TX_OK;
 }
 
+static int rh850_send_release_can_buffer_cmd(struct net_device *netdev)
+{
+       char *tx_buf, *rx_buf;
+       int ret;
+       struct spi_mosi *req;
+       struct rh850_can *priv_data;
+       struct rh850_netdev_privdata *netdev_priv_data;
+       int *mode;
+
+       netdev_priv_data = netdev_priv(netdev);
+       priv_data = netdev_priv_data->rh850_can;
+       mutex_lock(&priv_data->spi_lock);
+       tx_buf = priv_data->tx_buf;
+       rx_buf = priv_data->rx_buf;
+       memset(tx_buf, 0, XFER_BUFFER_SIZE);
+       memset(rx_buf, 0, XFER_BUFFER_SIZE);
+       priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+       req = (struct spi_mosi *)tx_buf;
+       req->cmd = CMD_CAN_RELEASE_BUFFER;
+       req->len = sizeof(int);
+       req->seq = atomic_inc_return(&priv_data->msg_seq);
+       mode = (int *)req->data;
+       *mode = priv_data->driver_mode;
+
+       ret = rh850_do_spi_transaction(priv_data);
+       mutex_unlock(&priv_data->spi_lock);
+
+       return ret;
+}
+
+static int rh850_data_buffering(struct net_device *netdev,
+                               struct ifreq *ifr, int cmd)
+{
+       char *tx_buf, *rx_buf;
+       int ret;
+       struct spi_mosi *req;
+       struct rh850_add_can_buffer *enable_buffering;
+       struct rh850_add_can_buffer *add_request;
+       struct rh850_can *priv_data;
+       struct rh850_netdev_privdata *netdev_priv_data;
+
+       netdev_priv_data = netdev_priv(netdev);
+       priv_data = netdev_priv_data->rh850_can;
+
+       mutex_lock(&priv_data->spi_lock);
+       tx_buf = priv_data->tx_buf;
+       rx_buf = priv_data->rx_buf;
+       memset(tx_buf, 0, XFER_BUFFER_SIZE);
+       memset(rx_buf, 0, XFER_BUFFER_SIZE);
+       priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+       add_request = ifr->ifr_data;
+       req = (struct spi_mosi *)tx_buf;
+
+       if (cmd == IOCTL_ENABLE_BUFFERING)
+               req->cmd = CMD_CAN_DATA_BUFF_ADD;
+       else
+               req->cmd = CMD_CAN_DATA_BUFF_REMOVE;
+
+       req->len = sizeof(struct rh850_add_can_buffer);
+       req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+       enable_buffering = (struct rh850_add_can_buffer *)req->data;
+       enable_buffering->can_if = add_request->can_if;
+       enable_buffering->mid = add_request->mid;
+       enable_buffering->mask = add_request->mask;
+
+       ret = rh850_do_spi_transaction(priv_data);
+       mutex_unlock(&priv_data->spi_lock);
+
+       return ret;
+}
+
+static int rh850_remove_all_buffering(struct net_device *netdev)
+{
+       char *tx_buf, *rx_buf;
+       int ret;
+       struct spi_mosi *req;
+       struct rh850_can *priv_data;
+       struct rh850_netdev_privdata *netdev_priv_data;
+
+       netdev_priv_data = netdev_priv(netdev);
+       priv_data = netdev_priv_data->rh850_can;
+
+       mutex_lock(&priv_data->spi_lock);
+       tx_buf = priv_data->tx_buf;
+       rx_buf = priv_data->rx_buf;
+       memset(tx_buf, 0, XFER_BUFFER_SIZE);
+       memset(rx_buf, 0, XFER_BUFFER_SIZE);
+       priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+       req = (struct spi_mosi *)tx_buf;
+       req->cmd = CMD_CAN_DATA_BUFF_REMOVE_ALL;
+       req->len = 0;
+       req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+       ret = rh850_do_spi_transaction(priv_data);
+       mutex_unlock(&priv_data->spi_lock);
+
+       return ret;
+}
+
+static int rh850_frame_filter(struct net_device *netdev,
+                             struct ifreq *ifr, int cmd)
+{
+       char *tx_buf, *rx_buf;
+       int ret;
+       struct spi_mosi *req;
+       struct can_add_filter_req *add_filter;
+       struct can_add_filter_req *filter_request;
+       struct rh850_can *priv_data;
+       struct rh850_netdev_privdata *netdev_priv_data;
+
+       netdev_priv_data = netdev_priv(netdev);
+       priv_data = netdev_priv_data->rh850_can;
+
+       mutex_lock(&priv_data->spi_lock);
+       tx_buf = priv_data->tx_buf;
+       rx_buf = priv_data->rx_buf;
+       memset(tx_buf, 0, XFER_BUFFER_SIZE);
+       memset(rx_buf, 0, XFER_BUFFER_SIZE);
+       priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+       filter_request = ifr->ifr_data;
+       req = (struct spi_mosi *)tx_buf;
+
+       if (cmd == IOCTL_ADD_FRAME_FILTER)
+               req->cmd = CMD_CAN_ADD_FILTER;
+       else
+               req->cmd = CMD_CAN_REMOVE_FILTER;
+
+       req->len = sizeof(struct can_add_filter_req);
+       req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+       add_filter = (struct can_add_filter_req *)req->data;
+       add_filter->can_if = filter_request->can_if;
+       add_filter->mid = filter_request->mid;
+       add_filter->mask = filter_request->mask;
+
+       ret = rh850_do_spi_transaction(priv_data);
+       mutex_unlock(&priv_data->spi_lock);
+
+       return ret;
+}
+
+static int rh850_send_spi_locked(struct rh850_can *priv_data, int cmd, int len,
+                                u8 *data)
+{
+       char *tx_buf, *rx_buf;
+       struct spi_mosi *req;
+       int ret;
+
+       LOGDI("rh850_send_spi_locked\n");
+
+       tx_buf = priv_data->tx_buf;
+       rx_buf = priv_data->rx_buf;
+       memset(tx_buf, 0, XFER_BUFFER_SIZE);
+       memset(rx_buf, 0, XFER_BUFFER_SIZE);
+       priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+       req = (struct spi_mosi *)tx_buf;
+       req->cmd = cmd;
+       req->len = len;
+       req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+       if (unlikely(len > 64))
+               return -EINVAL;
+       memcpy(req->data, data, len);
+
+       ret = rh850_do_spi_transaction(priv_data);
+       return ret;
+}
+
+static int rh850_convert_ioctl_cmd_to_spi_cmd(int ioctl_cmd)
+{
+       switch (ioctl_cmd) {
+       case IOCTL_GET_FW_BR_VERSION:
+               return CMD_GET_FW_BR_VERSION;
+       case IOCTL_BEGIN_FIRMWARE_UPGRADE:
+               return CMD_BEGIN_FIRMWARE_UPGRADE;
+       case IOCTL_FIRMWARE_UPGRADE_DATA:
+               return CMD_FIRMWARE_UPGRADE_DATA;
+       case IOCTL_END_FIRMWARE_UPGRADE:
+               return CMD_END_FIRMWARE_UPGRADE;
+       case IOCTL_BEGIN_BOOT_ROM_UPGRADE:
+               return CMD_BEGIN_BOOT_ROM_UPGRADE;
+       case IOCTL_BOOT_ROM_UPGRADE_DATA:
+               return CMD_BOOT_ROM_UPGRADE_DATA;
+       case IOCTL_END_BOOT_ROM_UPGRADE:
+               return CMD_END_BOOT_ROM_UPGRADE;
+       }
+       return -EINVAL;
+}
+
+static int rh850_do_blocking_ioctl(struct net_device *netdev,
+                                  struct ifreq *ifr, int cmd)
+{
+       int spi_cmd, ret;
+
+       struct rh850_can *priv_data;
+       struct rh850_netdev_privdata *netdev_priv_data;
+       struct rh850_ioctl_req *ioctl_data;
+       int len = 0;
+       u8 *data = NULL;
+
+       netdev_priv_data = netdev_priv(netdev);
+       priv_data = netdev_priv_data->rh850_can;
+
+       spi_cmd = rh850_convert_ioctl_cmd_to_spi_cmd(cmd);
+       LOGDI("rh850_do_blocking_ioctl spi_cmd %x\n", spi_cmd);
+       if (spi_cmd < 0) {
+               LOGDE("rh850_do_blocking_ioctl wrong command %d\n", cmd);
+               return spi_cmd;
+       }
+       if (!ifr)
+               return -EINVAL;
+       ioctl_data = ifr->ifr_data;
+       /* Regular NULL check fails here as ioctl_data is at some offset */
+       if ((void *)ioctl_data > (void *)0x100) {
+               len = ioctl_data->len;
+               data = ioctl_data->data;
+       }
+       LOGDI("rh850_do_blocking_ioctl len %d\n", len);
+       mutex_lock(&priv_data->spi_lock);
+
+       priv_data->wait_cmd = spi_cmd;
+       priv_data->cmd_result = -1;
+       reinit_completion(&priv_data->response_completion);
+
+       ret = rh850_send_spi_locked(priv_data, spi_cmd, len, data);
+       mutex_unlock(&priv_data->spi_lock);
+
+       if (ret == 0) {
+               LOGDI("rh850_do_blocking_ioctl ready to wait for response\n");
+               wait_for_completion_interruptible_timeout(
+                               &priv_data->response_completion, 5 * HZ);
+               ret = priv_data->cmd_result;
+       }
+       return ret;
+}
+
+static int rh850_netdev_do_ioctl(struct net_device *netdev,
+                                struct ifreq *ifr, int cmd)
+{
+       struct rh850_can *priv_data;
+       struct rh850_netdev_privdata *netdev_priv_data;
+       int *mode;
+       int ret = -EINVAL;
+
+       netdev_priv_data = netdev_priv(netdev);
+       priv_data = netdev_priv_data->rh850_can;
+       LOGDI("rh850_netdev_do_ioctl %x\n", cmd);
+
+       switch (cmd) {
+       case IOCTL_RELEASE_CAN_BUFFER:
+               if (ifr->ifr_data > (void *)0x100) {
+                       mode = ifr->ifr_data;
+                       priv_data->driver_mode = *mode;
+               }
+               LOGDE("rh850_driver_mode  %d\n", priv_data->driver_mode);
+               rh850_send_release_can_buffer_cmd(netdev);
+               ret = 0;
+               break;
+       case IOCTL_ENABLE_BUFFERING:
+       case IOCTL_DISABLE_BUFFERING:
+               rh850_data_buffering(netdev, ifr, cmd);
+               ret = 0;
+               break;
+       case IOCTL_DISABLE_ALL_BUFFERING:
+               rh850_remove_all_buffering(netdev);
+               ret = 0;
+               break;
+       case IOCTL_ADD_FRAME_FILTER:
+       case IOCTL_REMOVE_FRAME_FILTER:
+               rh850_frame_filter(netdev, ifr, cmd);
+               ret = 0;
+               break;
+       case IOCTL_GET_FW_BR_VERSION:
+       case IOCTL_BEGIN_FIRMWARE_UPGRADE:
+       case IOCTL_FIRMWARE_UPGRADE_DATA:
+       case IOCTL_END_FIRMWARE_UPGRADE:
+       case IOCTL_BEGIN_BOOT_ROM_UPGRADE:
+       case IOCTL_BOOT_ROM_UPGRADE_DATA:
+       case IOCTL_END_BOOT_ROM_UPGRADE:
+               ret = rh850_do_blocking_ioctl(netdev, ifr, cmd);
+               break;
+       }
+       LOGDI("rh850_netdev_do_ioctl ret %d\n", ret);
+
+       return ret;
+}
+
 static const struct net_device_ops rh850_netdev_ops = {
                .ndo_open = rh850_netdev_open,
                .ndo_stop = rh850_netdev_close,
                .ndo_start_xmit = rh850_netdev_start_xmit,
+               .ndo_do_ioctl = rh850_netdev_do_ioctl,
 };
 
 static int rh850_create_netdev(struct spi_device *spi,
@@ -490,9 +1029,13 @@ static int rh850_create_netdev(struct spi_device *spi,
        netdev->netdev_ops = &rh850_netdev_ops;
        SET_NETDEV_DEV(netdev, &spi->dev);
        netdev_priv_data->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
-                                                  CAN_CTRLMODE_LISTENONLY;
+                                                  CAN_CTRLMODE_LISTENONLY |
+                                                  CAN_CTRLMODE_FD;
        netdev_priv_data->can.bittiming_const = &rh850_bittiming_const;
+       netdev_priv_data->can.data_bittiming_const =
+                       &rh850_data_bittiming_const;
        netdev_priv_data->can.clock.freq = RH850_CLOCK;
+       netdev_priv_data->can.do_set_bittiming = rh850_set_bitrate;
 
        return 0;
 }
@@ -534,9 +1077,11 @@ static struct rh850_can *rh850_create_priv_data(struct spi_device *spi)
                goto cleanup_privdata;
        }
        priv_data->xfer_length = 0;
+       priv_data->driver_mode = DRIVER_MODE_RAW_FRAMES;
 
        mutex_init(&priv_data->spi_lock);
        atomic_set(&priv_data->msg_seq, 0);
+       init_completion(&priv_data->response_completion);
        return priv_data;
 
 cleanup_privdata:
index 7af870a..f9e4988 100644 (file)
@@ -58,7 +58,7 @@ static struct kobj_type ktype_veth_pool;
 
 static const char ibmveth_driver_name[] = "ibmveth";
 static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
-#define ibmveth_driver_version "1.05"
+#define ibmveth_driver_version "1.06"
 
 MODULE_AUTHOR("Santiago Leon <santil@linux.vnet.ibm.com>");
 MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
@@ -137,6 +137,11 @@ static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
        return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;
 }
 
+static inline int ibmveth_rxq_large_packet(struct ibmveth_adapter *adapter)
+{
+       return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_LRG_PKT;
+}
+
 static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
 {
        return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
@@ -1172,6 +1177,53 @@ map_failed:
        goto retry_bounce;
 }
 
+static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
+{
+       struct tcphdr *tcph;
+       int offset = 0;
+       int hdr_len;
+
+       /* only TCP packets will be aggregated */
+       if (skb->protocol == htons(ETH_P_IP)) {
+               struct iphdr *iph = (struct iphdr *)skb->data;
+
+               if (iph->protocol == IPPROTO_TCP) {
+                       offset = iph->ihl * 4;
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+               } else {
+                       return;
+               }
+       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               struct ipv6hdr *iph6 = (struct ipv6hdr *)skb->data;
+
+               if (iph6->nexthdr == IPPROTO_TCP) {
+                       offset = sizeof(struct ipv6hdr);
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+               } else {
+                       return;
+               }
+       } else {
+               return;
+       }
+       /* if mss is not set through Large Packet bit/mss in rx buffer,
+        * expect that the mss will be written to the tcp header checksum.
+        */
+       tcph = (struct tcphdr *)(skb->data + offset);
+       if (lrg_pkt) {
+               skb_shinfo(skb)->gso_size = mss;
+       } else if (offset) {
+               skb_shinfo(skb)->gso_size = ntohs(tcph->check);
+               tcph->check = 0;
+       }
+
+       if (skb_shinfo(skb)->gso_size) {
+               hdr_len = offset + tcph->doff * 4;
+               skb_shinfo(skb)->gso_segs =
+                               DIV_ROUND_UP(skb->len - hdr_len,
+                                            skb_shinfo(skb)->gso_size);
+       }
+}
+
 static int ibmveth_poll(struct napi_struct *napi, int budget)
 {
        struct ibmveth_adapter *adapter =
@@ -1180,6 +1232,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
        int frames_processed = 0;
        unsigned long lpar_rc;
        struct iphdr *iph;
+       u16 mss = 0;
 
 restart_poll:
        while (frames_processed < budget) {
@@ -1197,9 +1250,21 @@ restart_poll:
                        int length = ibmveth_rxq_frame_length(adapter);
                        int offset = ibmveth_rxq_frame_offset(adapter);
                        int csum_good = ibmveth_rxq_csum_good(adapter);
+                       int lrg_pkt = ibmveth_rxq_large_packet(adapter);
 
                        skb = ibmveth_rxq_get_buffer(adapter);
 
+                       /* if the large packet bit is set in the rx queue
+                        * descriptor, the mss will be written by PHYP eight
+                        * bytes from the start of the rx buffer, which is
+                        * skb->data at this stage
+                        */
+                       if (lrg_pkt) {
+                               __be64 *rxmss = (__be64 *)(skb->data + 8);
+
+                               mss = (u16)be64_to_cpu(*rxmss);
+                       }
+
                        new_skb = NULL;
                        if (length < rx_copybreak)
                                new_skb = netdev_alloc_skb(netdev, length);
@@ -1233,11 +1298,15 @@ restart_poll:
                                        if (iph->check == 0xffff) {
                                                iph->check = 0;
                                                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-                                               adapter->rx_large_packets++;
                                        }
                                }
                        }
 
+                       if (length > netdev->mtu + ETH_HLEN) {
+                               ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
+                               adapter->rx_large_packets++;
+                       }
+
                        napi_gro_receive(napi, skb);    /* send it up */
 
                        netdev->stats.rx_packets++;
index 4eade67..7acda04 100644 (file)
@@ -209,6 +209,7 @@ struct ibmveth_rx_q_entry {
 #define IBMVETH_RXQ_TOGGLE             0x80000000
 #define IBMVETH_RXQ_TOGGLE_SHIFT       31
 #define IBMVETH_RXQ_VALID              0x40000000
+#define IBMVETH_RXQ_LRG_PKT            0x04000000
 #define IBMVETH_RXQ_NO_CSUM            0x02000000
 #define IBMVETH_RXQ_CSUM_GOOD          0x01000000
 #define IBMVETH_RXQ_OFF_MASK           0x0000FFFF
index 3348e64..6eba580 100644 (file)
@@ -101,13 +101,19 @@ void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn)
 {
        struct mlx4_cq *cq;
 
+       rcu_read_lock();
        cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree,
                               cqn & (dev->caps.num_cqs - 1));
+       rcu_read_unlock();
+
        if (!cq) {
                mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn);
                return;
        }
 
+       /* Acessing the CQ outside of rcu_read_lock is safe, because
+        * the CQ is freed only after interrupt handling is completed.
+        */
        ++cq->arm_sn;
 
        cq->comp(cq);
@@ -118,23 +124,19 @@ void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type)
        struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
        struct mlx4_cq *cq;
 
-       spin_lock(&cq_table->lock);
-
+       rcu_read_lock();
        cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1));
-       if (cq)
-               atomic_inc(&cq->refcount);
-
-       spin_unlock(&cq_table->lock);
+       rcu_read_unlock();
 
        if (!cq) {
-               mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn);
+               mlx4_dbg(dev, "Async event for bogus CQ %08x\n", cqn);
                return;
        }
 
+       /* Acessing the CQ outside of rcu_read_lock is safe, because
+        * the CQ is freed only after interrupt handling is completed.
+        */
        cq->event(cq, event_type);
-
-       if (atomic_dec_and_test(&cq->refcount))
-               complete(&cq->free);
 }
 
 static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
@@ -301,9 +303,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
        if (err)
                return err;
 
-       spin_lock_irq(&cq_table->lock);
+       spin_lock(&cq_table->lock);
        err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
-       spin_unlock_irq(&cq_table->lock);
+       spin_unlock(&cq_table->lock);
        if (err)
                goto err_icm;
 
@@ -347,9 +349,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
        return 0;
 
 err_radix:
-       spin_lock_irq(&cq_table->lock);
+       spin_lock(&cq_table->lock);
        radix_tree_delete(&cq_table->tree, cq->cqn);
-       spin_unlock_irq(&cq_table->lock);
+       spin_unlock(&cq_table->lock);
 
 err_icm:
        mlx4_cq_free_icm(dev, cq->cqn);
@@ -368,15 +370,15 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
        if (err)
                mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
 
+       spin_lock(&cq_table->lock);
+       radix_tree_delete(&cq_table->tree, cq->cqn);
+       spin_unlock(&cq_table->lock);
+
        synchronize_irq(priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq);
        if (priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq !=
            priv->eq_table.eq[MLX4_EQ_ASYNC].irq)
                synchronize_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
 
-       spin_lock_irq(&cq_table->lock);
-       radix_tree_delete(&cq_table->tree, cq->cqn);
-       spin_unlock_irq(&cq_table->lock);
-
        if (atomic_dec_and_test(&cq->refcount))
                complete(&cq->free);
        wait_for_completion(&cq->free);
index 28a4b34..82bf1b5 100644 (file)
@@ -439,8 +439,14 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
                ring->cqn = priv->rx_cq[ring_ind]->mcq.cqn;
 
                ring->stride = stride;
-               if (ring->stride <= TXBB_SIZE)
+               if (ring->stride <= TXBB_SIZE) {
+                       /* Stamp first unused send wqe */
+                       __be32 *ptr = (__be32 *)ring->buf;
+                       __be32 stamp = cpu_to_be32(1 << STAMP_SHIFT);
+                       *ptr = stamp;
+                       /* Move pointer to start of rx section */
                        ring->buf += TXBB_SIZE;
+               }
 
                ring->log_stride = ffs(ring->stride) - 1;
                ring->buf_size = ring->size * ring->stride;
index d314d96..d1fc7fa 100644 (file)
@@ -2955,6 +2955,9 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
                put_res(dev, slave, srqn, RES_SRQ);
                qp->srq = srq;
        }
+
+       /* Save param3 for dynamic changes from VST back to VGT */
+       qp->param3 = qpc->param3;
        put_res(dev, slave, rcqn, RES_CQ);
        put_res(dev, slave, mtt_base, RES_MTT);
        res_end_move(dev, slave, RES_QP, qpn);
@@ -3747,7 +3750,6 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        int qpn = vhcr->in_modifier & 0x7fffff;
        struct res_qp *qp;
        u8 orig_sched_queue;
-       __be32  orig_param3 = qpc->param3;
        u8 orig_vlan_control = qpc->pri_path.vlan_control;
        u8 orig_fvl_rx = qpc->pri_path.fvl_rx;
        u8 orig_pri_path_fl = qpc->pri_path.fl;
@@ -3789,7 +3791,6 @@ out:
         */
        if (!err) {
                qp->sched_queue = orig_sched_queue;
-               qp->param3      = orig_param3;
                qp->vlan_control = orig_vlan_control;
                qp->fvl_rx      =  orig_fvl_rx;
                qp->pri_path_fl = orig_pri_path_fl;
index 4e2b26a..2aa1a1d 100644 (file)
@@ -777,7 +777,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct net_device *netdev;
        struct catc *catc;
        u8 broadcast[ETH_ALEN];
-       int i, pktsz;
+       int pktsz, ret;
 
        if (usb_set_interface(usbdev,
                        intf->altsetting->desc.bInterfaceNumber, 1)) {
@@ -812,12 +812,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
        if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
            (!catc->rx_urb) || (!catc->irq_urb)) {
                dev_err(&intf->dev, "No free urbs available.\n");
-               usb_free_urb(catc->ctrl_urb);
-               usb_free_urb(catc->tx_urb);
-               usb_free_urb(catc->rx_urb);
-               usb_free_urb(catc->irq_urb);
-               free_netdev(netdev);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto fail_free;
        }
 
        /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */
@@ -845,15 +841,24 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
        if (!catc->is_f5u011) {
+               u32 *buf;
+               int i;
+
                dev_dbg(dev, "Checking memory size\n");
 
-               i = 0x12345678;
-               catc_write_mem(catc, 0x7a80, &i, 4);
-               i = 0x87654321; 
-               catc_write_mem(catc, 0xfa80, &i, 4);
-               catc_read_mem(catc, 0x7a80, &i, 4);
+               buf = kmalloc(4, GFP_KERNEL);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto fail_free;
+               }
+
+               *buf = 0x12345678;
+               catc_write_mem(catc, 0x7a80, buf, 4);
+               *buf = 0x87654321;
+               catc_write_mem(catc, 0xfa80, buf, 4);
+               catc_read_mem(catc, 0x7a80, buf, 4);
          
-               switch (i) {
+               switch (*buf) {
                case 0x12345678:
                        catc_set_reg(catc, TxBufCount, 8);
                        catc_set_reg(catc, RxBufCount, 32);
@@ -868,6 +873,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                        dev_dbg(dev, "32k Memory\n");
                        break;
                }
+
+               kfree(buf);
          
                dev_dbg(dev, "Getting MAC from SEEROM.\n");
          
@@ -914,16 +921,21 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
        usb_set_intfdata(intf, catc);
 
        SET_NETDEV_DEV(netdev, &intf->dev);
-       if (register_netdev(netdev) != 0) {
-               usb_set_intfdata(intf, NULL);
-               usb_free_urb(catc->ctrl_urb);
-               usb_free_urb(catc->tx_urb);
-               usb_free_urb(catc->rx_urb);
-               usb_free_urb(catc->irq_urb);
-               free_netdev(netdev);
-               return -EIO;
-       }
+       ret = register_netdev(netdev);
+       if (ret)
+               goto fail_clear_intfdata;
+
        return 0;
+
+fail_clear_intfdata:
+       usb_set_intfdata(intf, NULL);
+fail_free:
+       usb_free_urb(catc->ctrl_urb);
+       usb_free_urb(catc->tx_urb);
+       usb_free_urb(catc->rx_urb);
+       usb_free_urb(catc->irq_urb);
+       free_netdev(netdev);
+       return ret;
 }
 
 static void catc_disconnect(struct usb_interface *intf)
index f840802..17fac01 100644 (file)
@@ -126,40 +126,61 @@ static void async_ctrl_callback(struct urb *urb)
 
 static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
+       u8 *buf;
        int ret;
 
+       buf = kmalloc(size, GFP_NOIO);
+       if (!buf)
+               return -ENOMEM;
+
        ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
                              PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
-                             indx, data, size, 1000);
+                             indx, buf, size, 1000);
        if (ret < 0)
                netif_dbg(pegasus, drv, pegasus->net,
                          "%s returned %d\n", __func__, ret);
+       else if (ret <= size)
+               memcpy(data, buf, ret);
+       kfree(buf);
        return ret;
 }
 
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
+                        const void *data)
 {
+       u8 *buf;
        int ret;
 
+       buf = kmemdup(data, size, GFP_NOIO);
+       if (!buf)
+               return -ENOMEM;
+
        ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
                              PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
-                             indx, data, size, 100);
+                             indx, buf, size, 100);
        if (ret < 0)
                netif_dbg(pegasus, drv, pegasus->net,
                          "%s returned %d\n", __func__, ret);
+       kfree(buf);
        return ret;
 }
 
 static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
 {
+       u8 *buf;
        int ret;
 
+       buf = kmemdup(&data, 1, GFP_NOIO);
+       if (!buf)
+               return -ENOMEM;
+
        ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
                              PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
-                             indx, &data, 1, 1000);
+                             indx, buf, 1, 1000);
        if (ret < 0)
                netif_dbg(pegasus, drv, pegasus->net,
                          "%s returned %d\n", __func__, ret);
+       kfree(buf);
        return ret;
 }
 
index d37b7dc..3967298 100644 (file)
@@ -155,16 +155,36 @@ static const char driver_name [] = "rtl8150";
 */
 static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-       return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
-                              RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-                              indx, 0, data, size, 500);
+       void *buf;
+       int ret;
+
+       buf = kmalloc(size, GFP_NOIO);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+                             RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+                             indx, 0, buf, size, 500);
+       if (ret > 0 && ret <= size)
+               memcpy(data, buf, ret);
+       kfree(buf);
+       return ret;
 }
 
-static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
 {
-       return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
-                              RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-                              indx, 0, data, size, 500);
+       void *buf;
+       int ret;
+
+       buf = kmemdup(data, size, GFP_NOIO);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+                             RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+                             indx, 0, buf, size, 500);
+       kfree(buf);
+       return ret;
 }
 
 static void async_set_reg_cb(struct urb *urb)
index 84a9b1a..9bab797 100644 (file)
@@ -13,6 +13,7 @@
 #include <soc/qcom/subsystem_restart.h>
 #include <soc/qcom/service-notifier.h>
 #include <soc/qcom/msm_qmi_interface.h>
+#include <soc/qcom/icnss.h>
 #include <soc/qcom/service-locator.h>
 #include "core.h"
 #include "qmi.h"
@@ -448,6 +449,7 @@ int ath10k_snoc_qmi_wlan_enable(struct ath10k *ar,
        int ret;
        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
        struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+       unsigned long time_left;
 
        ath10k_dbg(ar, ATH10K_DBG_SNOC,
                   "Mode: %d, config: %p, host_version: %s\n",
@@ -461,10 +463,15 @@ int ath10k_snoc_qmi_wlan_enable(struct ath10k *ar,
                return ret;
        }
 
-       wait_event_timeout(ath10k_fw_ready_wait_event,
+       time_left = wait_event_timeout(
+                          ath10k_fw_ready_wait_event,
                           (atomic_read(&qmi_cfg->fw_ready) &&
                            atomic_read(&qmi_cfg->server_connected)),
                           msecs_to_jiffies(ATH10K_SNOC_WLAN_FW_READY_TIMEOUT));
+       if (time_left == 0) {
+               ath10k_err(ar, "Wait for FW ready and server connect timed out\n");
+               return -ETIMEDOUT;
+       }
 
        req.host_version_valid = 1;
        strlcpy(req.host_version, host_version,
@@ -854,9 +861,21 @@ int ath10k_snoc_start_qmi_service(struct ath10k *ar)
                goto out_destroy_wq;
        }
 
+       if (!icnss_is_fw_ready()) {
+               ath10k_err(ar, "failed to get fw ready indication\n");
+               ret = -EFAULT;
+               goto err_fw_ready;
+       }
+
+       atomic_set(&qmi_cfg->fw_ready, 1);
        ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI service started successfully\n");
        return 0;
 
+err_fw_ready:
+       qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
+                                         WLFW_SERVICE_VERS_V01,
+                                         WLFW_SERVICE_INS_ID_V01,
+                                         &qmi_cfg->wlfw_clnt_nb);
 out_destroy_wq:
        destroy_workqueue(qmi_cfg->event_wq);
        return ret;
index 2cbc8ee..08618ce 100644 (file)
@@ -1329,6 +1329,8 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
        if (!ar_snoc)
                return -EINVAL;
 
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__);
+
        ath10k_core_unregister(ar);
        ath10k_snoc_pdr_unregister_notifier(ar);
        ath10k_snoc_modem_ssr_unregister_notifier(ar);
@@ -1338,8 +1340,6 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
        ath10k_snoc_stop_qmi_service(ar);
        ath10k_core_destroy(ar);
 
-       ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__);
-
        return 0;
 }
 
index a876271..0394573 100644 (file)
@@ -528,6 +528,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
        if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
                return 0;
 
+       if (!spec_priv->rfs_chan_spec_scan)
+               return 1;
+
        /* Output buffers are full, no need to process anything
         * since there is no space to put the result anyway
         */
@@ -1072,7 +1075,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = {
 
 void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
 {
-       if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
+       if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) {
                relay_close(spec_priv->rfs_chan_spec_scan);
                spec_priv->rfs_chan_spec_scan = NULL;
        }
@@ -1086,6 +1089,9 @@ void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv,
                                            debugfs_phy,
                                            1024, 256, &rfs_spec_scan_cb,
                                            NULL);
+       if (!spec_priv->rfs_chan_spec_scan)
+               return;
+
        debugfs_create_file("spectral_scan_ctl",
                            S_IRUSR | S_IWUSR,
                            debugfs_phy, spec_priv,
index 3789814..423cdec 100644 (file)
@@ -26,6 +26,10 @@ bool disable_ap_sme;
 module_param(disable_ap_sme, bool, 0444);
 MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
 
+static bool ignore_reg_hints = true;
+module_param(ignore_reg_hints, bool, 0444);
+MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)");
+
 #define CHAN60G(_channel, _flags) {                            \
        .band                   = IEEE80211_BAND_60GHZ,         \
        .center_freq            = 56160 + (2160 * (_channel)),  \
@@ -1743,6 +1747,11 @@ static void wil_wiphy_init(struct wiphy *wiphy)
        wiphy->vendor_commands = wil_nl80211_vendor_commands;
        wiphy->vendor_events = wil_nl80211_vendor_events;
        wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events);
+
+       if (ignore_reg_hints) {
+               wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
+               wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
+       }
 }
 
 struct wireless_dev *wil_cfg80211_init(struct device *dev)
index 09c37c2..af64b3d 100644 (file)
@@ -228,6 +228,7 @@ void wcnss_prealloc_check_memory_leak(void)
 #else
 void wcnss_prealloc_check_memory_leak(void) {}
 #endif
+EXPORT_SYMBOL(wcnss_prealloc_check_memory_leak);
 
 int wcnss_pre_alloc_reset(void)
 {
@@ -243,6 +244,7 @@ int wcnss_pre_alloc_reset(void)
 
        return n;
 }
+EXPORT_SYMBOL(wcnss_pre_alloc_reset);
 
 int prealloc_memory_stats_show(struct seq_file *fp, void *data)
 {
index 6df3ee5..515aa3f 100644 (file)
@@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
        spin_lock_bh(&local->baplock);
 
        res = hfa384x_setup_bap(dev, BAP0, rid, 0);
-       if (!res)
-               res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+       if (res)
+               goto unlock;
+
+       res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+       if (res)
+               goto unlock;
 
        if (le16_to_cpu(rec.len) == 0) {
                /* RID not available */
                res = -ENODATA;
+               goto unlock;
        }
 
        rlen = (le16_to_cpu(rec.len) - 1) * 2;
-       if (!res && exact_len && rlen != len) {
+       if (exact_len && rlen != len) {
                printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
                       "rid=0x%04x, len=%d (expected %d)\n",
                       dev->name, rid, rlen, len);
                res = -ENODATA;
        }
 
-       if (!res)
-               res = hfa384x_from_bap(dev, BAP0, buf, len);
+       res = hfa384x_from_bap(dev, BAP0, buf, len);
 
+unlock:
        spin_unlock_bh(&local->baplock);
        mutex_unlock(&local->rid_bap_mtx);
 
index 5f47356..254b0ee 100644 (file)
@@ -590,8 +590,14 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
        rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len);
        if (rc < 0)
                goto out_unlock;
+       nvdimm_bus_unlock(&nvdimm_bus->dev);
+
        if (copy_to_user(p, buf, buf_len))
                rc = -EFAULT;
+
+       vfree(buf);
+       return rc;
+
  out_unlock:
        nvdimm_bus_unlock(&nvdimm_bus->dev);
  out:
index f364882..243afbe 100644 (file)
@@ -6754,12 +6754,12 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev,
                PCIE_DBG(pcie_dev, "RC%d: PM_Enter_L23 is NOT received\n",
                        pcie_dev->rc_idx);
 
-               msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
-
        if (pcie_dev->use_pinctrl && pcie_dev->pins_sleep)
                pinctrl_select_state(pcie_dev->pinctrl,
                                        pcie_dev->pins_sleep);
 
+       msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
+
        PCIE_DBG(pcie_dev, "RC%d: exit\n", pcie_dev->rc_idx);
 
        return ret;
index 80e1657..dc05d71 100644 (file)
@@ -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
 #include <linux/interrupt.h>
 #include <linux/of_gpio.h>
 #include <linux/gpio.h>
-#include <linux/power_supply.h>
+#include <linux/extcon.h>
 #include <linux/regulator/consumer.h>
 
 struct gpio_usbdetect {
        struct platform_device  *pdev;
        struct regulator        *vin;
-       struct power_supply     *usb_psy;
        int                     vbus_det_irq;
+       int                     id_det_irq;
        int                     gpio;
+       struct extcon_dev       *extcon_dev;
+       int                     vbus_state;
+       bool                    id_state;
+};
+
+static const unsigned int gpio_usb_extcon_table[] = {
+       EXTCON_USB,
+       EXTCON_USB_HOST,
+       EXTCON_USB_CC,
+       EXTCON_USB_SPEED,
+       EXTCON_NONE,
 };
 
 static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data)
 {
        struct gpio_usbdetect *usb = data;
-       int vbus;
-       union power_supply_propval pval = {0,};
 
-       vbus = gpio_get_value(usb->gpio);
-       if (vbus)
-               pval.intval = POWER_SUPPLY_TYPE_USB;
-       else
-               pval.intval = POWER_SUPPLY_TYPE_UNKNOWN;
+       usb->vbus_state = gpio_get_value(usb->gpio);
+       if (usb->vbus_state) {
+               dev_dbg(&usb->pdev->dev, "setting vbus notification\n");
+               extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1);
+       } else {
+               dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n");
+               extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t gpio_usbdetect_id_irq(int irq, void *data)
+{
+       struct gpio_usbdetect *usb = data;
+       int ret;
+
+       ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL,
+                       &usb->id_state);
+       if (ret < 0) {
+               dev_err(&usb->pdev->dev, "unable to read ID IRQ LINE\n");
+               return IRQ_HANDLED;
+       }
 
-       power_supply_set_property(usb->usb_psy,
-                       POWER_SUPPLY_PROP_TYPE, &pval);
+       return IRQ_WAKE_THREAD;
+}
 
-       pval.intval = vbus;
-       power_supply_set_property(usb->usb_psy, POWER_SUPPLY_PROP_PRESENT,
-                       &pval);
+static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data)
+{
+       struct gpio_usbdetect *usb = data;
+
+       if (usb->id_state) {
+               dev_dbg(&usb->pdev->dev, "stopping usb host\n");
+               extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0);
+               enable_irq(usb->vbus_det_irq);
+       } else {
+               dev_dbg(&usb->pdev->dev, "starting usb HOST\n");
+               disable_irq(usb->vbus_det_irq);
+               extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1);
+       }
        return IRQ_HANDLED;
 }
 
+static const u32 gpio_usb_extcon_exclusive[] = {0x3, 0};
+
 static int gpio_usbdetect_probe(struct platform_device *pdev)
 {
        struct gpio_usbdetect *usb;
-       struct power_supply *usb_psy;
        int rc;
-       unsigned long flags;
-
-       usb_psy = power_supply_get_by_name("usb");
-       if (!usb_psy) {
-               dev_dbg(&pdev->dev, "USB power_supply not found, deferring probe\n");
-               return -EPROBE_DEFER;
-       }
 
        usb = devm_kzalloc(&pdev->dev, sizeof(*usb), GFP_KERNEL);
        if (!usb)
                return -ENOMEM;
 
        usb->pdev = pdev;
-       usb->usb_psy = usb_psy;
+
+       usb->extcon_dev = devm_extcon_dev_allocate(&pdev->dev,
+                       gpio_usb_extcon_table);
+       if (IS_ERR(usb->extcon_dev)) {
+               dev_err(&pdev->dev, "failed to allocate a extcon device\n");
+               return PTR_ERR(usb->extcon_dev);
+       }
+
+       usb->extcon_dev->mutually_exclusive = gpio_usb_extcon_exclusive;
+       rc = devm_extcon_dev_register(&pdev->dev, usb->extcon_dev);
+       if (rc) {
+               dev_err(&pdev->dev, "failed to register extcon device\n");
+               return rc;
+       }
 
        if (of_get_property(pdev->dev.of_node, "vin-supply", NULL)) {
                usb->vin = devm_regulator_get(&pdev->dev, "vin");
@@ -94,43 +138,63 @@ static int gpio_usbdetect_probe(struct platform_device *pdev)
                                "qcom,vbus-det-gpio", 0);
        if (usb->gpio < 0) {
                dev_err(&pdev->dev, "Failed to get gpio: %d\n", usb->gpio);
-               return usb->gpio;
+               rc = usb->gpio;
+               goto error;
        }
 
        rc = gpio_request(usb->gpio, "vbus-det-gpio");
        if (rc < 0) {
                dev_err(&pdev->dev, "Failed to request gpio: %d\n", rc);
-               return rc;
+               goto error;
        }
 
        usb->vbus_det_irq = gpio_to_irq(usb->gpio);
        if (usb->vbus_det_irq < 0) {
-               if (usb->vin)
-                       regulator_disable(usb->vin);
-               return usb->vbus_det_irq;
+               dev_err(&pdev->dev, "get vbus_det_irq failed\n");
+               rc = usb->vbus_det_irq;
+               goto error;
        }
 
-       rc = devm_request_irq(&pdev->dev, usb->vbus_det_irq,
-                             gpio_usbdetect_vbus_irq,
-                             IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                             "vbus_det_irq", usb);
+       rc = devm_request_threaded_irq(&pdev->dev, usb->vbus_det_irq,
+                               NULL, gpio_usbdetect_vbus_irq,
+                             IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                             IRQF_ONESHOT, "vbus_det_irq", usb);
        if (rc) {
                dev_err(&pdev->dev, "request for vbus_det_irq failed: %d\n",
                        rc);
-               if (usb->vin)
-                       regulator_disable(usb->vin);
-               return rc;
+               goto error;
+       }
+
+       usb->id_det_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
+       if (usb->id_det_irq < 0) {
+               dev_err(&pdev->dev, "get id_det_irq failed\n");
+               rc = usb->id_det_irq;
+               goto error;
+       }
+
+       rc = devm_request_threaded_irq(&pdev->dev, usb->id_det_irq,
+                               gpio_usbdetect_id_irq,
+                               gpio_usbdetect_id_irq_thread,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                               IRQF_ONESHOT, "id_det_irq", usb);
+       if (rc) {
+               dev_err(&pdev->dev, "request for id_det_irq failed: %d\n", rc);
+               goto error;
        }
 
        enable_irq_wake(usb->vbus_det_irq);
+       enable_irq_wake(usb->id_det_irq);
        dev_set_drvdata(&pdev->dev, usb);
 
        /* Read and report initial VBUS state */
-       local_irq_save(flags);
        gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb);
-       local_irq_restore(flags);
 
        return 0;
+
+error:
+       if (usb->vin)
+               regulator_disable(usb->vin);
+       return rc;
 }
 
 static int gpio_usbdetect_remove(struct platform_device *pdev)
@@ -139,6 +203,8 @@ static int gpio_usbdetect_remove(struct platform_device *pdev)
 
        disable_irq_wake(usb->vbus_det_irq);
        disable_irq(usb->vbus_det_irq);
+       disable_irq_wake(usb->id_det_irq);
+       disable_irq(usb->id_det_irq);
        if (usb->vin)
                regulator_disable(usb->vin);
 
index f01743d..0629d6b 100644 (file)
@@ -3685,6 +3685,7 @@ void ipa_suspend_handler(enum ipa_irq_type interrupt,
                                 * pipe will be unsuspended as part of
                                 * enabling IPA clocks
                                 */
+                               mutex_lock(&ipa_ctx->sps_pm.sps_pm_lock);
                                if (!atomic_read(
                                        &ipa_ctx->sps_pm.dec_clients)
                                        ) {
@@ -3697,6 +3698,7 @@ void ipa_suspend_handler(enum ipa_irq_type interrupt,
                                                1);
                                        ipa_sps_process_irq_schedule_rel();
                                }
+                               mutex_unlock(&ipa_ctx->sps_pm.sps_pm_lock);
                        } else {
                                resource = ipa2_get_rm_resource_from_ep(i);
                                res = ipa_rm_request_resource_with_timer(
index 5ee6e5d..5a7a0e5 100644 (file)
@@ -3614,6 +3614,8 @@ void ipa3_suspend_handler(enum ipa_irq_type interrupt,
                                 * pipe will be unsuspended as part of
                                 * enabling IPA clocks
                                 */
+                               mutex_lock(&ipa3_ctx->transport_pm.
+                                       transport_pm_mutex);
                                if (!atomic_read(
                                        &ipa3_ctx->transport_pm.dec_clients)
                                        ) {
@@ -3626,6 +3628,8 @@ void ipa3_suspend_handler(enum ipa_irq_type interrupt,
                                        1);
                                        ipa3_sps_process_irq_schedule_rel();
                                }
+                               mutex_unlock(&ipa3_ctx->transport_pm.
+                                       transport_pm_mutex);
                        } else {
                                resource = ipa3_get_rm_resource_from_ep(i);
                                res =
index c5b56f1..f230627 100644 (file)
@@ -1515,6 +1515,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
        struct ipa3_ep_context *ep;
        int empty;
        int result;
+       int i;
 
        if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
            ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1551,7 +1552,17 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
                cancel_delayed_work_sync(&ep->sys->replenish_rx_work);
        flush_workqueue(ep->sys->wq);
        if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               result = ipa3_stop_gsi_channel(clnt_hdl);
+               /* channel stop might fail on timeout if IPA is busy */
+               for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+                       result = ipa3_stop_gsi_channel(clnt_hdl);
+                       if (result == GSI_STATUS_SUCCESS)
+                               break;
+
+                       if (result != -GSI_STATUS_AGAIN &&
+                           result != -GSI_STATUS_TIMED_OUT)
+                               break;
+               }
+
                if (result != GSI_STATUS_SUCCESS) {
                        IPAERR("GSI stop chan err: %d.\n", result);
                        BUG();
index 335e528..0269bfb 100644 (file)
@@ -53,6 +53,8 @@ struct ipa3_qmi_context *ipa3_qmi_ctx;
 static bool workqueues_stopped;
 static bool ipa3_modem_init_cmplt;
 static bool first_time_handshake;
+struct mutex ipa3_qmi_lock;
+
 /* QMI A5 service */
 
 static struct msg_desc ipa3_indication_reg_req_desc = {
@@ -610,12 +612,17 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req)
                req->filter_spec_ex_list_len);
        }
 
-       /* cache the qmi_filter_request */
-       memcpy(&(ipa3_qmi_ctx->ipa_install_fltr_rule_req_msg_cache[
-               ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg]),
-                       req, sizeof(struct ipa_install_fltr_rule_req_msg_v01));
-       ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg++;
-       ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg %= 10;
+       mutex_lock(&ipa3_qmi_lock);
+       if (ipa3_qmi_ctx != NULL) {
+               /* cache the qmi_filter_request */
+               memcpy(&(ipa3_qmi_ctx->ipa_install_fltr_rule_req_msg_cache[
+                       ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg]),
+                       req,
+                       sizeof(struct ipa_install_fltr_rule_req_msg_v01));
+               ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg++;
+               ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg %= 10;
+       }
+       mutex_unlock(&ipa3_qmi_lock);
 
        req_desc.max_msg_len = QMI_IPA_INSTALL_FILTER_RULE_REQ_MAX_MSG_LEN_V01;
        req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_REQ_V01;
@@ -655,12 +662,17 @@ int ipa3_qmi_filter_request_ex_send(
                req->filter_spec_ex_list_len);
        }
 
-       /* cache the qmi_filter_request */
-       memcpy(&(ipa3_qmi_ctx->ipa_install_fltr_rule_req_ex_msg_cache[
-               ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg]),
-               req, sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01));
-       ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg++;
-       ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg %= 10;
+       mutex_lock(&ipa3_qmi_lock);
+       if (ipa3_qmi_ctx != NULL) {
+               /* cache the qmi_filter_request */
+               memcpy(&(ipa3_qmi_ctx->ipa_install_fltr_rule_req_ex_msg_cache[
+                       ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg]),
+                       req,
+                       sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01));
+               ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg++;
+               ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg %= 10;
+       }
+       mutex_unlock(&ipa3_qmi_lock);
 
        req_desc.max_msg_len =
                QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01;
@@ -795,12 +807,17 @@ int ipa3_qmi_filter_notify_send(
                return -EINVAL;
        }
 
-       /* cache the qmi_filter_request */
-       memcpy(&(ipa3_qmi_ctx->ipa_fltr_installed_notif_req_msg_cache[
-               ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg]),
-               req, sizeof(struct ipa_fltr_installed_notif_req_msg_v01));
-       ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg++;
-       ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg %= 10;
+       mutex_lock(&ipa3_qmi_lock);
+       if (ipa3_qmi_ctx != NULL) {
+               /* cache the qmi_filter_request */
+               memcpy(&(ipa3_qmi_ctx->ipa_fltr_installed_notif_req_msg_cache[
+                       ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg]),
+                       req,
+                       sizeof(struct ipa_fltr_installed_notif_req_msg_v01));
+               ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg++;
+               ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg %= 10;
+       }
+       mutex_unlock(&ipa3_qmi_lock);
 
        req_desc.max_msg_len =
        QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_MAX_MSG_LEN_V01;
@@ -1338,3 +1355,13 @@ int ipa3_qmi_stop_data_qouta(void)
                resp.resp.error, "ipa_stop_data_usage_quota_req_msg_v01");
 }
 
+void ipa3_qmi_init(void)
+{
+       mutex_init(&ipa3_qmi_lock);
+}
+
+void ipa3_qmi_cleanup(void)
+{
+       mutex_destroy(&ipa3_qmi_lock);
+}
+
index 0442004..6cd82f8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -204,6 +204,10 @@ int ipa3_qmi_stop_data_qouta(void);
 
 void ipa3_q6_handshake_complete(bool ssr_bootup);
 
+void ipa3_qmi_init(void);
+
+void ipa3_qmi_cleanup(void);
+
 #else /* CONFIG_RMNET_IPA3 */
 
 static inline int ipa3_qmi_service_init(uint32_t wan_platform_type)
@@ -316,6 +320,14 @@ static inline int ipa3_qmi_stop_data_qouta(void)
 
 static inline void ipa3_q6_handshake_complete(bool ssr_bootup) { }
 
+static inline void ipa3_qmi_init(void)
+{
+}
+
+static inline void ipa3_qmi_cleanup(void)
+{
+}
+
 #endif /* CONFIG_RMNET_IPA3 */
 
 #endif /* IPA_QMI_SERVICE_H */
index 57fa246..e49bdc8 100644 (file)
@@ -1205,6 +1205,8 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in,
                IPADBG("Skipping endpoint configuration.\n");
        }
 
+       ipa3_enable_data_path(ipa_ep_idx);
+
        out->clnt_hdl = ipa_ep_idx;
 
        if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
index f4a7319..5ffc1f2 100644 (file)
@@ -3582,21 +3582,30 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
 
        memset(&mem, 0, sizeof(mem));
 
+       if (IPA_CLIENT_IS_PROD(ep->client)) {
+               IPADBG("Calling gsi_stop_channel ch:%lu\n",
+                       ep->gsi_chan_hdl);
+               res = gsi_stop_channel(ep->gsi_chan_hdl);
+               IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+                       ep->gsi_chan_hdl, res);
+               goto end_sequence;
+       }
+
        for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
-               IPADBG("Calling gsi_stop_channel\n");
+               IPADBG("Calling gsi_stop_channel ch:%lu\n",
+                       ep->gsi_chan_hdl);
                res = gsi_stop_channel(ep->gsi_chan_hdl);
-               IPADBG("gsi_stop_channel returned %d\n", res);
+               IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+                       ep->gsi_chan_hdl, res);
                if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
                        goto end_sequence;
 
-               if (IPA_CLIENT_IS_CONS(ep->client)) {
-                       IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
-                       /* Send a 1B packet DMA_TASK to IPA and try again */
-                       res = ipa3_inject_dma_task_for_gsi();
-                       if (res) {
-                               IPAERR("Failed to inject DMA TASk for GSI\n");
-                               goto end_sequence;
-                       }
+               IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
+               /* Send a 1B packet DMA_TASK to IPA and try again */
+               res = ipa3_inject_dma_task_for_gsi();
+               if (res) {
+                       IPAERR("Failed to inject DMA TASk for GSI\n");
+                       goto end_sequence;
                }
 
                /* sleep for short period to flush IPA */
index 258c086..04e5862 100644 (file)
@@ -3214,6 +3214,9 @@ static int __init ipa3_wwan_init(void)
        mutex_init(&rmnet_ipa3_ctx->pipe_handle_guard);
        rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
        rmnet_ipa3_ctx->apps_to_ipa3_hdl = -1;
+
+       ipa3_qmi_init();
+
        /* Register for Modem SSR */
        rmnet_ipa3_ctx->subsys_notify_handle = subsys_notif_register_notifier(
                        SUBSYS_MODEM,
@@ -3227,6 +3230,7 @@ static int __init ipa3_wwan_init(void)
 static void __exit ipa3_wwan_cleanup(void)
 {
        int ret;
+       ipa3_qmi_cleanup();
        mutex_destroy(&rmnet_ipa3_ctx->pipe_handle_guard);
        ret = subsys_notif_unregister_notifier(
                rmnet_ipa3_ctx->subsys_notify_handle, &ipa3_ssr_notifier);
index 1062fa4..b2cdc1a 100644 (file)
@@ -1816,11 +1816,24 @@ static int __init acer_wmi_enable_lm(void)
        return status;
 }
 
+#define ACER_WMID_ACCEL_HID    "BST0001"
+
 static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
                                                void *ctx, void **retval)
 {
+       struct acpi_device *dev;
+
+       if (!strcmp(ctx, "SENR")) {
+               if (acpi_bus_get_device(ah, &dev))
+                       return AE_OK;
+               if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
+                       return AE_OK;
+       } else
+               return AE_OK;
+
        *(acpi_handle *)retval = ah;
-       return AE_OK;
+
+       return AE_CTRL_TERMINATE;
 }
 
 static int __init acer_wmi_get_handle(const char *name, const char *prop,
@@ -1847,7 +1860,7 @@ static int __init acer_wmi_accel_setup(void)
 {
        int err;
 
-       err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+       err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
        if (err)
                return err;
 
@@ -2185,10 +2198,11 @@ static int __init acer_wmi_init(void)
                err = acer_wmi_input_setup();
                if (err)
                        return err;
+               err = acer_wmi_accel_setup();
+               if (err)
+                       return err;
        }
 
-       acer_wmi_accel_setup();
-
        err = platform_driver_register(&acer_platform_driver);
        if (err) {
                pr_err("Unable to register platform driver\n");
index 723b9ea..8d7322a 100644 (file)
@@ -114,7 +114,8 @@ static ssize_t power_supply_show_property(struct device *dev,
                return sprintf(buf, "%s\n", technology_text[value.intval]);
        else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
                return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
-       else if (off == POWER_SUPPLY_PROP_TYPE)
+       else if (off == POWER_SUPPLY_PROP_TYPE ||
+                       off == POWER_SUPPLY_PROP_REAL_TYPE)
                return sprintf(buf, "%s\n", type_text[value.intval]);
        else if (off == POWER_SUPPLY_PROP_SCOPE)
                return sprintf(buf, "%s\n", scope_text[value.intval]);
@@ -294,6 +295,7 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(connector_health),
        POWER_SUPPLY_ATTR(ctm_current_max),
        POWER_SUPPLY_ATTR(hw_current_max),
+       POWER_SUPPLY_ATTR(real_type),
        /* Local extensions of type int64_t */
        POWER_SUPPLY_ATTR(charge_counter_ext),
        /* Properties of type `const char *' */
index e9e24df..2579f02 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/printk.h>
 
+#include <soc/at91/at91sam9_ddrsdr.h>
+
 #define AT91_SHDW_CR   0x00            /* Shut Down Control Register */
 #define AT91_SHDW_SHDW         BIT(0)                  /* Shut Down command */
 #define AT91_SHDW_KEY          (0xa5 << 24)            /* KEY Password */
@@ -50,6 +53,7 @@ static const char *shdwc_wakeup_modes[] = {
 
 static void __iomem *at91_shdwc_base;
 static struct clk *sclk;
+static void __iomem *mpddrc_base;
 
 static void __init at91_wakeup_status(void)
 {
@@ -73,6 +77,29 @@ static void at91_poweroff(void)
        writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
 }
 
+static void at91_lpddr_poweroff(void)
+{
+       asm volatile(
+               /* Align to cache lines */
+               ".balign 32\n\t"
+
+               /* Ensure AT91_SHDW_CR is in the TLB by reading it */
+               "       ldr     r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
+
+               /* Power down SDRAM0 */
+               "       str     %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
+               /* Shutdown CPU */
+               "       str     %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
+
+               "       b       .\n\t"
+               :
+               : "r" (mpddrc_base),
+                 "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
+                 "r" (at91_shdwc_base),
+                 "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
+               : "r0");
+}
+
 static int at91_poweroff_get_wakeup_mode(struct device_node *np)
 {
        const char *pm;
@@ -124,6 +151,8 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
 static int __init at91_poweroff_probe(struct platform_device *pdev)
 {
        struct resource *res;
+       struct device_node *np;
+       u32 ddr_type;
        int ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -150,12 +179,30 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
 
        pm_power_off = at91_poweroff;
 
+       np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
+       if (!np)
+               return 0;
+
+       mpddrc_base = of_iomap(np, 0);
+       of_node_put(np);
+
+       if (!mpddrc_base)
+               return 0;
+
+       ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
+       if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
+           (ddr_type == AT91_DDRSDRC_MD_LPDDR3))
+               pm_power_off = at91_lpddr_poweroff;
+       else
+               iounmap(mpddrc_base);
+
        return 0;
 }
 
 static int __exit at91_poweroff_remove(struct platform_device *pdev)
 {
-       if (pm_power_off == at91_poweroff)
+       if (pm_power_off == at91_poweroff ||
+           pm_power_off == at91_lpddr_poweroff)
                pm_power_off = NULL;
 
        clk_disable_unprepare(sclk);
@@ -163,6 +210,11 @@ static int __exit at91_poweroff_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id at91_ramc_of_match[] = {
+       { .compatible = "atmel,sama5d3-ddramc", },
+       { /* sentinel */ }
+};
+
 static const struct of_device_id at91_poweroff_of_match[] = {
        { .compatible = "atmel,at91sam9260-shdwc", },
        { .compatible = "atmel,at91sam9rl-shdwc", },
index 8d038ba..acea4f2 100644 (file)
@@ -497,13 +497,13 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr,
        if (sysfs_streq(buf, "full")) {
                dload_type = SCM_DLOAD_FULLDUMP;
        } else if (sysfs_streq(buf, "mini")) {
-               if (!msm_minidump_enabled()) {
-                       pr_info("Minidump is not enabled\n");
+               if (!minidump_enabled) {
+                       pr_err("Minidump is not enabled\n");
                        return -ENODEV;
                }
                dload_type = SCM_DLOAD_MINIDUMP;
        } else {
-               pr_info("Invalid value. Use 'full' or 'mini'\n");
+               pr_err("Invalid value. Use 'full' or 'mini'\n");
                return -EINVAL;
        }
 
index 539e757..98d75f5 100644 (file)
@@ -410,19 +410,6 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
        if (!chip->main_psy)
                return 0;
 
-       if (chip->batt_psy) {
-               rc = power_supply_get_property(chip->batt_psy,
-                       POWER_SUPPLY_PROP_CURRENT_QNOVO,
-                       &pval);
-               if (rc < 0) {
-                       pr_err("Couldn't get qnovo fcc, rc=%d\n", rc);
-                       return rc;
-               }
-
-               if (pval.intval != -EINVAL)
-                       total_fcc_ua = pval.intval;
-       }
-
        if (chip->pl_mode == POWER_SUPPLY_PL_NONE
            || get_effective_result_locked(chip->pl_disable_votable)) {
                pval.intval = total_fcc_ua;
@@ -473,7 +460,6 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
        struct pl_data *chip = data;
        union power_supply_propval pval = {0, };
        int rc = 0;
-       int effective_fv_uv = fv_uv;
 
        if (fv_uv < 0)
                return 0;
@@ -481,20 +467,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
        if (!chip->main_psy)
                return 0;
 
-       if (chip->batt_psy) {
-               rc = power_supply_get_property(chip->batt_psy,
-                       POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
-                       &pval);
-               if (rc < 0) {
-                       pr_err("Couldn't get qnovo fv, rc=%d\n", rc);
-                       return rc;
-               }
-
-               if (pval.intval != -EINVAL)
-                       effective_fv_uv = pval.intval;
-       }
-
-       pval.intval = effective_fv_uv;
+       pval.intval = fv_uv;
 
        rc = power_supply_set_property(chip->main_psy,
                        POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
@@ -930,11 +903,17 @@ static int pl_determine_initial_status(struct pl_data *chip)
 }
 
 #define DEFAULT_RESTRICTED_CURRENT_UA  1000000
-static int pl_init(void)
+int qcom_batt_init(void)
 {
        struct pl_data *chip;
        int rc = 0;
 
+       /* initialize just once */
+       if (the_chip) {
+               pr_err("was initialized earlier Failing now\n");
+               return -EINVAL;
+       }
+
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
@@ -1014,7 +993,9 @@ static int pl_init(void)
                goto unreg_notifier;
        }
 
-       return rc;
+       the_chip = chip;
+
+       return 0;
 
 unreg_notifier:
        power_supply_unreg_notifier(&chip->nb);
@@ -1031,21 +1012,23 @@ cleanup:
        return rc;
 }
 
-static void pl_deinit(void)
+void qcom_batt_deinit(void)
 {
        struct pl_data *chip = the_chip;
 
+       if (chip == NULL)
+               return;
+
+       cancel_work_sync(&chip->status_change_work);
+       cancel_delayed_work_sync(&chip->pl_taper_work);
+       cancel_work_sync(&chip->pl_disable_forever_work);
+
        power_supply_unreg_notifier(&chip->nb);
        destroy_votable(chip->pl_awake_votable);
        destroy_votable(chip->pl_disable_votable);
        destroy_votable(chip->fv_votable);
        destroy_votable(chip->fcc_votable);
        wakeup_source_unregister(chip->pl_ws);
+       the_chip = NULL;
        kfree(chip);
 }
-
-module_init(pl_init);
-module_exit(pl_deinit)
-
-MODULE_DESCRIPTION("");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h
new file mode 100644 (file)
index 0000000..38626e7
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __BATTERY_H
+#define __BATTERY_H
+int qcom_batt_init(void);
+void qcom_batt_deinit(void);
+#endif /* __BATTERY_H */
index 8855a1c..94b9e9c 100644 (file)
@@ -238,11 +238,9 @@ static struct smb_params pm660_params = {
 
 #define STEP_CHARGING_MAX_STEPS        5
 struct smb_dt_props {
-       int     fcc_ua;
        int     usb_icl_ua;
        int     dc_icl_ua;
        int     boost_threshold_ua;
-       int     fv_uv;
        int     wipower_max_uw;
        int     min_freq_khz;
        int     max_freq_khz;
@@ -310,14 +308,14 @@ static int smb2_parse_dt(struct smb2 *chip)
                                                "qcom,external-vconn");
 
        rc = of_property_read_u32(node,
-                               "qcom,fcc-max-ua", &chip->dt.fcc_ua);
+                               "qcom,fcc-max-ua", &chg->batt_profile_fcc_ua);
        if (rc < 0)
-               chip->dt.fcc_ua = -EINVAL;
+               chg->batt_profile_fcc_ua = -EINVAL;
 
        rc = of_property_read_u32(node,
-                               "qcom,fv-max-uv", &chip->dt.fv_uv);
+                               "qcom,fv-max-uv", &chg->batt_profile_fv_uv);
        if (rc < 0)
-               chip->dt.fv_uv = -EINVAL;
+               chg->batt_profile_fv_uv = -EINVAL;
 
        rc = of_property_read_u32(node,
                                "qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
@@ -429,6 +427,7 @@ static enum power_supply_property smb2_usb_props[] = {
        POWER_SUPPLY_PROP_PE_START,
        POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
        POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+       POWER_SUPPLY_PROP_REAL_TYPE,
 };
 
 static int smb2_usb_get_prop(struct power_supply *psy,
@@ -448,6 +447,16 @@ static int smb2_usb_get_prop(struct power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_ONLINE:
                rc = smblib_get_prop_usb_online(chg, val);
+               if (!val->intval)
+                       break;
+
+               rc = smblib_get_prop_typec_mode(chg, val);
+               if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+                       chg->micro_usb_mode) &&
+                       chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+                       val->intval = 0;
+               else
+                       val->intval = 1;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN:
                val->intval = chg->voltage_min_uv;
@@ -465,10 +474,13 @@ static int smb2_usb_get_prop(struct power_supply *psy,
                rc = smblib_get_prop_usb_current_max(chg, val);
                break;
        case POWER_SUPPLY_PROP_TYPE:
+               val->intval = POWER_SUPPLY_TYPE_USB_PD;
+               break;
+       case POWER_SUPPLY_PROP_REAL_TYPE:
                if (chip->bad_part)
-                       val->intval = POWER_SUPPLY_TYPE_USB;
+                       val->intval = POWER_SUPPLY_TYPE_USB_PD;
                else
-                       val->intval = chg->usb_psy_desc.type;
+                       val->intval = chg->real_charger_type;
                break;
        case POWER_SUPPLY_PROP_TYPEC_MODE:
                if (chg->micro_usb_mode)
@@ -610,7 +622,7 @@ static int smb2_init_usb_psy(struct smb2 *chip)
        struct smb_charger *chg = &chip->chg;
 
        chg->usb_psy_desc.name                  = "usb";
-       chg->usb_psy_desc.type                  = POWER_SUPPLY_TYPE_UNKNOWN;
+       chg->usb_psy_desc.type                  = POWER_SUPPLY_TYPE_USB_PD;
        chg->usb_psy_desc.properties            = smb2_usb_props;
        chg->usb_psy_desc.num_properties        = ARRAY_SIZE(smb2_usb_props);
        chg->usb_psy_desc.get_property          = smb2_usb_get_prop;
@@ -619,7 +631,7 @@ static int smb2_init_usb_psy(struct smb2 *chip)
 
        usb_cfg.drv_data = chip;
        usb_cfg.of_node = chg->dev->of_node;
-       chg->usb_psy = devm_power_supply_register(chg->dev,
+       chg->usb_psy = power_supply_register(chg->dev,
                                                  &chg->usb_psy_desc,
                                                  &usb_cfg);
        if (IS_ERR(chg->usb_psy)) {
@@ -630,6 +642,97 @@ static int smb2_init_usb_psy(struct smb2 *chip)
        return 0;
 }
 
+/********************************
+ * USB PC_PORT PSY REGISTRATION *
+ ********************************/
+static enum power_supply_property smb2_usb_port_props[] = {
+       POWER_SUPPLY_PROP_TYPE,
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int smb2_usb_port_get_prop(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct smb2 *chip = power_supply_get_drvdata(psy);
+       struct smb_charger *chg = &chip->chg;
+       int rc = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_TYPE:
+               val->intval = POWER_SUPPLY_TYPE_USB;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               rc = smblib_get_prop_usb_online(chg, val);
+               if (!val->intval)
+                       break;
+
+               rc = smblib_get_prop_typec_mode(chg, val);
+               if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+                       chg->micro_usb_mode) &&
+                       chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+                       val->intval = 1;
+               else
+                       val->intval = 0;
+               break;
+       default:
+               pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
+                               psp);
+               return -EINVAL;
+       }
+
+       if (rc < 0) {
+               pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+               return -ENODATA;
+       }
+
+       return 0;
+}
+
+static int smb2_usb_port_set_prop(struct power_supply *psy,
+               enum power_supply_property psp,
+               const union power_supply_propval *val)
+{
+       int rc = 0;
+
+       switch (psp) {
+       default:
+               pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
+                               psp);
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
+
+static const struct power_supply_desc usb_port_psy_desc = {
+       .name           = "pc_port",
+       .type           = POWER_SUPPLY_TYPE_USB,
+       .properties     = smb2_usb_port_props,
+       .num_properties = ARRAY_SIZE(smb2_usb_port_props),
+       .get_property   = smb2_usb_port_get_prop,
+       .set_property   = smb2_usb_port_set_prop,
+};
+
+static int smb2_init_usb_port_psy(struct smb2 *chip)
+{
+       struct power_supply_config usb_port_cfg = {};
+       struct smb_charger *chg = &chip->chg;
+
+       usb_port_cfg.drv_data = chip;
+       usb_port_cfg.of_node = chg->dev->of_node;
+       chg->usb_port_psy = power_supply_register(chg->dev,
+                                                 &usb_port_psy_desc,
+                                                 &usb_port_cfg);
+       if (IS_ERR(chg->usb_port_psy)) {
+               pr_err("Couldn't register USB pc_port power supply\n");
+               return PTR_ERR(chg->usb_port_psy);
+       }
+
+       return 0;
+}
+
 /*****************************
  * USB MAIN PSY REGISTRATION *
  *****************************/
@@ -677,7 +780,7 @@ static int smb2_usb_main_get_prop(struct power_supply *psy,
                rc = smblib_get_prop_fcc_delta(chg, val);
                break;
        case POWER_SUPPLY_PROP_CURRENT_MAX:
-               val->intval = get_effective_result(chg->usb_icl_votable);
+               rc = smblib_get_icl_current(chg, &val->intval);
                break;
        default:
                pr_debug("get prop %d is not supported in usb-main\n", psp);
@@ -734,7 +837,7 @@ static int smb2_init_usb_main_psy(struct smb2 *chip)
 
        usb_main_cfg.drv_data = chip;
        usb_main_cfg.of_node = chg->dev->of_node;
-       chg->usb_main_psy = devm_power_supply_register(chg->dev,
+       chg->usb_main_psy = power_supply_register(chg->dev,
                                                  &usb_main_psy_desc,
                                                  &usb_main_cfg);
        if (IS_ERR(chg->usb_main_psy)) {
@@ -836,7 +939,7 @@ static int smb2_init_dc_psy(struct smb2 *chip)
 
        dc_cfg.drv_data = chip;
        dc_cfg.of_node = chg->dev->of_node;
-       chg->dc_psy = devm_power_supply_register(chg->dev,
+       chg->dc_psy = power_supply_register(chg->dev,
                                                  &dc_psy_desc,
                                                  &dc_cfg);
        if (IS_ERR(chg->dc_psy)) {
@@ -942,13 +1045,15 @@ static int smb2_batt_get_prop(struct power_supply *psy,
                rc = smblib_get_prop_charge_qnovo_enable(chg, val);
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
-               val->intval = chg->qnovo_fv_uv;
+               val->intval = get_client_vote_locked(chg->fv_votable,
+                               QNOVO_VOTER);
                break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                rc = smblib_get_prop_batt_current_now(chg, val);
                break;
        case POWER_SUPPLY_PROP_CURRENT_QNOVO:
-               val->intval = chg->qnovo_fcc_ua;
+               val->intval = get_client_vote_locked(chg->fcc_votable,
+                               QNOVO_VOTER);
                break;
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
                val->intval = get_client_vote(chg->fcc_votable,
@@ -1014,23 +1119,37 @@ static int smb2_batt_set_prop(struct power_supply *psy,
                vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MAX:
-               vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval);
+               chg->batt_profile_fv_uv = val->intval;
+               vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
                break;
        case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
                rc = smblib_set_prop_charge_qnovo_enable(chg, val);
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
-               chg->qnovo_fv_uv = val->intval;
-               rc = rerun_election(chg->fv_votable);
+               if (val->intval == -EINVAL) {
+                       vote(chg->fv_votable, BATT_PROFILE_VOTER,
+                                       true, chg->batt_profile_fv_uv);
+                       vote(chg->fv_votable, QNOVO_VOTER, false, 0);
+               } else {
+                       vote(chg->fv_votable, QNOVO_VOTER, true, val->intval);
+                       vote(chg->fv_votable, BATT_PROFILE_VOTER, false, 0);
+               }
                break;
        case POWER_SUPPLY_PROP_CURRENT_QNOVO:
-               chg->qnovo_fcc_ua = val->intval;
                vote(chg->pl_disable_votable, PL_QNOVO_VOTER,
                        val->intval != -EINVAL && val->intval < 2000000, 0);
-               rc = rerun_election(chg->fcc_votable);
+               if (val->intval == -EINVAL) {
+                       vote(chg->fcc_votable, BATT_PROFILE_VOTER,
+                                       true, chg->batt_profile_fcc_ua);
+                       vote(chg->fcc_votable, QNOVO_VOTER, false, 0);
+               } else {
+                       vote(chg->fcc_votable, QNOVO_VOTER, true, val->intval);
+                       vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0);
+               }
                break;
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
-               vote(chg->fcc_votable, DEFAULT_VOTER, true, val->intval);
+               chg->batt_profile_fcc_ua = val->intval;
+               vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
                break;
        case POWER_SUPPLY_PROP_SET_SHIP_MODE:
                /* Not in ship mode as long as the device is active */
@@ -1047,6 +1166,9 @@ static int smb2_batt_set_prop(struct power_supply *psy,
        case POWER_SUPPLY_PROP_DP_DM:
                rc = smblib_dp_dm(chg, val->intval);
                break;
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+               rc = smblib_set_prop_input_current_limited(chg, val);
+               break;
        default:
                rc = -EINVAL;
        }
@@ -1064,6 +1186,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy,
        case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
        case POWER_SUPPLY_PROP_DP_DM:
        case POWER_SUPPLY_PROP_RERUN_AICL:
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
                return 1;
        default:
                break;
@@ -1090,7 +1213,7 @@ static int smb2_init_batt_psy(struct smb2 *chip)
 
        batt_cfg.drv_data = chg;
        batt_cfg.of_node = chg->dev->of_node;
-       chg->batt_psy = devm_power_supply_register(chg->dev,
+       chg->batt_psy = power_supply_register(chg->dev,
                                                   &batt_psy_desc,
                                                   &batt_cfg);
        if (IS_ERR(chg->batt_psy)) {
@@ -1447,11 +1570,13 @@ static int smb2_init_hw(struct smb2 *chip)
        if (chip->dt.no_battery)
                chg->fake_capacity = 50;
 
-       if (chip->dt.fcc_ua < 0)
-               smblib_get_charge_param(chg, &chg->param.fcc, &chip->dt.fcc_ua);
+       if (chg->batt_profile_fcc_ua < 0)
+               smblib_get_charge_param(chg, &chg->param.fcc,
+                               &chg->batt_profile_fcc_ua);
 
-       if (chip->dt.fv_uv < 0)
-               smblib_get_charge_param(chg, &chg->param.fv, &chip->dt.fv_uv);
+       if (chg->batt_profile_fv_uv < 0)
+               smblib_get_charge_param(chg, &chg->param.fv,
+                               &chg->batt_profile_fv_uv);
 
        smblib_get_charge_param(chg, &chg->param.usb_icl,
                                &chg->default_icl_ua);
@@ -1512,9 +1637,9 @@ static int smb2_init_hw(struct smb2 *chip)
        vote(chg->dc_suspend_votable,
                DEFAULT_VOTER, chip->dt.no_battery, 0);
        vote(chg->fcc_votable,
-               DEFAULT_VOTER, true, chip->dt.fcc_ua);
+               BATT_PROFILE_VOTER, true, chg->batt_profile_fcc_ua);
        vote(chg->fv_votable,
-               DEFAULT_VOTER, true, chip->dt.fv_uv);
+               BATT_PROFILE_VOTER, true, chg->batt_profile_fv_uv);
        vote(chg->dc_icl_votable,
                DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
        vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
@@ -2058,6 +2183,21 @@ static int smb2_request_interrupts(struct smb2 *chip)
        return rc;
 }
 
+static void smb2_free_interrupts(struct smb_charger *chg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(smb2_irqs); i++) {
+               if (smb2_irqs[i].irq > 0) {
+                       if (smb2_irqs[i].wake)
+                               disable_irq_wake(smb2_irqs[i].irq);
+
+                       devm_free_irq(chg->dev, smb2_irqs[i].irq,
+                                       smb2_irqs[i].irq_data);
+               }
+       }
+}
+
 static void smb2_disable_interrupts(struct smb_charger *chg)
 {
        int i;
@@ -2235,7 +2375,13 @@ static int smb2_probe(struct platform_device *pdev)
 
        rc = smb2_init_usb_main_psy(chip);
        if (rc < 0) {
-               pr_err("Couldn't initialize usb psy rc=%d\n", rc);
+               pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
+               goto cleanup;
+       }
+
+       rc = smb2_init_usb_port_psy(chip);
+       if (rc < 0) {
+               pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
                goto cleanup;
        }
 
@@ -2293,20 +2439,29 @@ static int smb2_probe(struct platform_device *pdev)
        device_init_wakeup(chg->dev, true);
 
        pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
-               usb_present, chg->usb_psy_desc.type,
+               usb_present, chg->real_charger_type,
                batt_present, batt_health, batt_charge_type);
        return rc;
 
 cleanup:
-       smblib_deinit(chg);
-       if (chg->usb_psy)
-               power_supply_unregister(chg->usb_psy);
+       smb2_free_interrupts(chg);
        if (chg->batt_psy)
                power_supply_unregister(chg->batt_psy);
+       if (chg->usb_main_psy)
+               power_supply_unregister(chg->usb_main_psy);
+       if (chg->usb_psy)
+               power_supply_unregister(chg->usb_psy);
+       if (chg->usb_port_psy)
+               power_supply_unregister(chg->usb_port_psy);
+       if (chg->dc_psy)
+               power_supply_unregister(chg->dc_psy);
        if (chg->vconn_vreg && chg->vconn_vreg->rdev)
-               regulator_unregister(chg->vconn_vreg->rdev);
+               devm_regulator_unregister(chg->dev, chg->vconn_vreg->rdev);
        if (chg->vbus_vreg && chg->vbus_vreg->rdev)
-               regulator_unregister(chg->vbus_vreg->rdev);
+               devm_regulator_unregister(chg->dev, chg->vbus_vreg->rdev);
+
+       smblib_deinit(chg);
+
        platform_set_drvdata(pdev, NULL);
        return rc;
 }
@@ -2318,6 +2473,7 @@ static int smb2_remove(struct platform_device *pdev)
 
        power_supply_unregister(chg->batt_psy);
        power_supply_unregister(chg->usb_psy);
+       power_supply_unregister(chg->usb_port_psy);
        regulator_unregister(chg->vconn_vreg->rdev);
        regulator_unregister(chg->vbus_vreg->rdev);
 
index 1e417e8..a191391 100644 (file)
 #include <linux/qpnp/qpnp-revid.h>
 #include <linux/input/qpnp-power-on.h>
 #include <linux/irq.h>
+#include <linux/pmic-voter.h>
 #include "smb-lib.h"
 #include "smb-reg.h"
+#include "battery.h"
 #include "storm-watch.h"
-#include <linux/pmic-voter.h>
 
 #define smblib_err(chg, fmt, ...)              \
        pr_err("%s: %s: " fmt, chg->name,       \
@@ -549,9 +550,9 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
 
        /* if PD is active, APSD is disabled so won't have a valid result */
        if (chg->pd_active)
-               chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
+               chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
        else
-               chg->usb_psy_desc.type = apsd_result->pst;
+               chg->real_charger_type = apsd_result->pst;
 
        smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
                                        apsd_result->name, chg->pd_active);
@@ -813,6 +814,28 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua)
        return rc;
 }
 
+static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
+{
+       int rc;
+       u8 icl_options;
+       bool usb3 = false;
+
+       rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
+               return rc;
+       }
+
+       usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
+
+       if (icl_options & USB51_MODE_BIT)
+               *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
+       else
+               *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
+
+       return rc;
+}
+
 int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
 {
        int rc = 0;
@@ -835,7 +858,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
 
        /* configure current */
        if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
-               && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
+               && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
                rc = set_sdp_current(chg, icl_ua);
                if (rc < 0) {
                        smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
@@ -856,10 +879,10 @@ override_suspend_config:
                /* remove override if no voters - hw defaults is desired */
                override = false;
        } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
-               if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
+               if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
                        /* For std cable with type = SDP never override */
                        override = false;
-               else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP
+               else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
                        && icl_ua == 1500000)
                        /*
                         * For std cable with type = CDP override only if
@@ -890,6 +913,48 @@ enable_icl_changed_interrupt:
        return rc;
 }
 
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
+{
+       int rc = 0;
+       u8 load_cfg;
+       bool override;
+       union power_supply_propval pval;
+
+       rc = smblib_get_prop_typec_mode(chg, &pval);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
+               return rc;
+       }
+
+       if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+               || chg->micro_usb_mode)
+               && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
+               rc = get_sdp_current(chg, icl_ua);
+               if (rc < 0) {
+                       smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
+                       return rc;
+               }
+       } else {
+               rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
+               if (rc < 0) {
+                       smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
+                       return rc;
+               }
+               override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
+               if (!override)
+                       return INT_MAX;
+
+               /* override is set */
+               rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
+               if (rc < 0) {
+                       smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
 /*********************
  * VOTABLE CALLBACKS *
  *********************/
@@ -1642,6 +1707,11 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg,
        u8 stat;
        int rc;
 
+       if (chg->fake_input_current_limited >= 0) {
+               val->intval = chg->fake_input_current_limited;
+               return 0;
+       }
+
        rc = smblib_read(chg, AICL_STATUS_REG, &stat);
        if (rc < 0) {
                smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
@@ -1833,6 +1903,13 @@ int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
        return rc;
 }
 
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+                               const union power_supply_propval *val)
+{
+       chg->fake_input_current_limited = val->intval;
+       return 0;
+}
+
 int smblib_rerun_aicl(struct smb_charger *chg)
 {
        int rc, settled_icl_ua;
@@ -2816,7 +2893,7 @@ int smblib_get_prop_fcc_delta(struct smb_charger *chg,
 int smblib_get_charge_current(struct smb_charger *chg,
                                int *total_current_ua)
 {
-       const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
+       const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
        union power_supply_propval val = {0, };
        int rc = 0, typec_source_rd, current_ua;
        bool non_compliant;
@@ -3088,12 +3165,28 @@ static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
        }
 }
 
-static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
 {
+       int rc;
+       u8 stat;
+       bool vbus_rising;
+
+       rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+       if (rc < 0) {
+               smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+               return;
+       }
+
+       vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+
        if (vbus_rising)
                smblib_cc2_sink_removal_exit(chg);
        else
                smblib_cc2_sink_removal_enter(chg);
+
+       power_supply_changed(chg->usb_psy);
+       smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+                                       vbus_rising ? "attached" : "detached");
 }
 
 #define PL_DELAY_MS                    30000
@@ -3152,8 +3245,6 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
 
        if (chg->micro_usb_mode)
                smblib_micro_usb_plugin(chg, vbus_rising);
-       else
-               smblib_typec_usb_plugin(chg, vbus_rising);
 
        power_supply_changed(chg->usb_psy);
        smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
@@ -3166,7 +3257,10 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
        struct smb_charger *chg = irq_data->parent_data;
 
        mutex_lock(&chg->lock);
-       smblib_usb_plugin_locked(chg);
+       if (chg->pd_hard_reset)
+               smblib_usb_plugin_hard_reset_locked(chg);
+       else
+               smblib_usb_plugin_locked(chg);
        mutex_unlock(&chg->lock);
        return IRQ_HANDLED;
 }
@@ -3232,7 +3326,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
        int pulses;
 
        power_supply_changed(chg->usb_main_psy);
-       if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+       if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
                rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
                if (rc < 0) {
                        smblib_err(chg,
@@ -3260,7 +3354,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
                }
        }
 
-       if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
+       if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
                rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
                if (rc < 0) {
                        smblib_err(chg,
@@ -3330,7 +3424,7 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
 static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
                                              bool rising, bool qc_charger)
 {
-       const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
+       const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
 
        /* Hold off PD only until hvdcp 2.0 detection timeout */
        if (rising) {
@@ -4187,26 +4281,30 @@ static int smblib_create_votables(struct smb_charger *chg)
        int rc = 0;
 
        chg->fcc_votable = find_votable("FCC");
-       if (!chg->fcc_votable) {
-               rc = -EPROBE_DEFER;
+       if (chg->fcc_votable == NULL) {
+               rc = -EINVAL;
+               smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
                return rc;
        }
 
        chg->fv_votable = find_votable("FV");
-       if (!chg->fv_votable) {
-               rc = -EPROBE_DEFER;
+       if (chg->fv_votable == NULL) {
+               rc = -EINVAL;
+               smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
                return rc;
        }
 
        chg->usb_icl_votable = find_votable("USB_ICL");
        if (!chg->usb_icl_votable) {
-               rc = -EPROBE_DEFER;
+               rc = -EINVAL;
+               smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
                return rc;
        }
 
        chg->pl_disable_votable = find_votable("PL_DISABLE");
-       if (!chg->pl_disable_votable) {
-               rc = -EPROBE_DEFER;
+       if (chg->pl_disable_votable == NULL) {
+               rc = -EINVAL;
+               smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
                return rc;
        }
        vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
@@ -4385,11 +4483,17 @@ int smblib_init(struct smb_charger *chg)
        INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
        INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
        chg->fake_capacity = -EINVAL;
+       chg->fake_input_current_limited = -EINVAL;
 
        switch (chg->mode) {
        case PARALLEL_MASTER:
-               chg->qnovo_fcc_ua = -EINVAL;
-               chg->qnovo_fv_uv = -EINVAL;
+               rc = qcom_batt_init();
+               if (rc < 0) {
+                       smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
+                               rc);
+                       return rc;
+               }
+
                rc = smblib_create_votables(chg);
                if (rc < 0) {
                        smblib_err(chg, "Couldn't create votables rc=%d\n",
@@ -4421,8 +4525,20 @@ int smblib_deinit(struct smb_charger *chg)
 {
        switch (chg->mode) {
        case PARALLEL_MASTER:
+               cancel_work_sync(&chg->bms_update_work);
+               cancel_work_sync(&chg->rdstd_cc2_detach_work);
+               cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+               cancel_delayed_work_sync(&chg->step_soc_req_work);
+               cancel_delayed_work_sync(&chg->clear_hdc_work);
+               cancel_work_sync(&chg->otg_oc_work);
+               cancel_work_sync(&chg->vconn_oc_work);
+               cancel_delayed_work_sync(&chg->otg_ss_done_work);
+               cancel_delayed_work_sync(&chg->icl_change_work);
+               cancel_delayed_work_sync(&chg->pl_enable_work);
+               cancel_work_sync(&chg->legacy_detection_work);
                power_supply_unreg_notifier(&chg->nb);
                smblib_destroy_votables(chg);
+               qcom_batt_deinit();
                break;
        case PARALLEL_SLAVE:
                break;
index b0d84f0..5dc60ec 100644 (file)
@@ -62,6 +62,8 @@ enum print_reason {
 #define AICL_RERUN_VOTER               "AICL_RERUN_VOTER"
 #define LEGACY_UNKNOWN_VOTER           "LEGACY_UNKNOWN_VOTER"
 #define CC2_WA_VOTER                   "CC2_WA_VOTER"
+#define QNOVO_VOTER                    "QNOVO_VOTER"
+#define BATT_PROFILE_VOTER             "BATT_PROFILE_VOTER"
 
 #define VCONN_MAX_ATTEMPTS     3
 #define OTG_MAX_ATTEMPTS       3
@@ -242,6 +244,8 @@ struct smb_charger {
        struct power_supply             *bms_psy;
        struct power_supply_desc        usb_psy_desc;
        struct power_supply             *usb_main_psy;
+       struct power_supply             *usb_port_psy;
+       enum power_supply_type          real_charger_type;
 
        /* notifiers */
        struct notifier_block   nb;
@@ -314,6 +318,7 @@ struct smb_charger {
        bool                    typec_present;
        u8                      typec_status[5];
        bool                    typec_legacy_valid;
+       int                     fake_input_current_limited;
 
        /* workaround flag */
        u32                     wa_flags;
@@ -325,9 +330,11 @@ struct smb_charger {
        /* extcon for VBUS / ID notification to USB for uUSB */
        struct extcon_dev       *extcon;
 
+       /* battery profile */
+       int                     batt_profile_fcc_ua;
+       int                     batt_profile_fv_uv;
+
        /* qnovo */
-       int                     qnovo_fcc_ua;
-       int                     qnovo_fv_uv;
        int                     usb_icl_delta_ua;
        int                     pulse_cnt;
 };
@@ -415,6 +422,8 @@ int smblib_set_prop_batt_capacity(struct smb_charger *chg,
                                const union power_supply_propval *val);
 int smblib_set_prop_system_temp_level(struct smb_charger *chg,
                                const union power_supply_propval *val);
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+                               const union power_supply_propval *val);
 
 int smblib_get_prop_dc_present(struct smb_charger *chg,
                                union power_supply_propval *val);
@@ -493,6 +502,7 @@ int smblib_icl_override(struct smb_charger *chg, bool override);
 int smblib_dp_dm(struct smb_charger *chg, int val);
 int smblib_rerun_aicl(struct smb_charger *chg);
 int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
 int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
 
 int smblib_init(struct smb_charger *chg);
index 3f260a4..167666a 100644 (file)
@@ -1025,14 +1025,4 @@ enum {
 /* CHGR FREQ Peripheral registers */
 #define FREQ_CLK_DIV_REG                       (CHGR_FREQ_BASE + 0x50)
 
-/* SMB1355 specific registers */
-#define SMB1355_TEMP_COMP_STATUS_REG           (MISC_BASE + 0x07)
-#define SKIN_TEMP_RST_HOT_BIT                  BIT(6)
-#define SKIN_TEMP_UB_HOT_BIT                   BIT(5)
-#define SKIN_TEMP_LB_HOT_BIT                   BIT(4)
-#define DIE_TEMP_TSD_HOT_BIT                   BIT(3)
-#define DIE_TEMP_RST_HOT_BIT                   BIT(2)
-#define DIE_TEMP_UB_HOT_BIT                    BIT(1)
-#define DIE_TEMP_LB_HOT_BIT                    BIT(0)
-
 #endif /* __SMB2_CHARGER_REG_H */
index 4e710ca..694591c 100644 (file)
@@ -104,8 +104,6 @@ struct smb138x {
        struct smb_dt_props     dt;
        struct power_supply     *parallel_psy;
        u32                     wa_flags;
-       struct pmic_revid_data  *pmic_rev_id;
-       char                    *name;
 };
 
 static int __debug_mask;
@@ -169,14 +167,6 @@ static int smb138x_parse_dt(struct smb138x *chip)
        if (rc < 0)
                chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
 
-       /* check that smb1355 is configured to run in mid-mid mode */
-       if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE
-               && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) {
-               pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n",
-                               chip->dt.pl_mode);
-               return -EINVAL;
-       }
-
        chip->dt.suspend_input = of_property_read_bool(node,
                                "qcom,suspend-input");
 
@@ -489,30 +479,6 @@ static int smb138x_init_batt_psy(struct smb138x *chip)
  * PARALLEL PSY REGISTRATION *
  *****************************/
 
-static int smb1355_get_prop_connector_health(struct smb138x *chip)
-{
-       struct smb_charger *chg = &chip->chg;
-       u8 temp;
-       int rc;
-
-       rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp);
-       if (rc < 0) {
-               pr_err("Couldn't read comp stat reg rc = %d\n", rc);
-               return POWER_SUPPLY_HEALTH_UNKNOWN;
-       }
-
-       if (temp & SKIN_TEMP_RST_HOT_BIT)
-               return POWER_SUPPLY_HEALTH_OVERHEAT;
-
-       if (temp & SKIN_TEMP_UB_HOT_BIT)
-               return POWER_SUPPLY_HEALTH_HOT;
-
-       if (temp & SKIN_TEMP_LB_HOT_BIT)
-               return POWER_SUPPLY_HEALTH_WARM;
-
-       return POWER_SUPPLY_HEALTH_COOL;
-}
-
 static int smb138x_get_prop_connector_health(struct smb138x *chip)
 {
        struct smb_charger *chg = &chip->chg;
@@ -570,32 +536,16 @@ static enum power_supply_property smb138x_parallel_props[] = {
        POWER_SUPPLY_PROP_PIN_ENABLED,
        POWER_SUPPLY_PROP_INPUT_SUSPEND,
        POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+       POWER_SUPPLY_PROP_CURRENT_MAX,
        POWER_SUPPLY_PROP_VOLTAGE_MAX,
        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
-       POWER_SUPPLY_PROP_MODEL_NAME,
-       POWER_SUPPLY_PROP_PARALLEL_MODE,
-       POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
-       POWER_SUPPLY_PROP_SET_SHIP_MODE,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CHARGER_TEMP,
        POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
-       POWER_SUPPLY_PROP_CURRENT_NOW,
-       POWER_SUPPLY_PROP_CURRENT_MAX,
-};
-
-static enum power_supply_property smb1355_parallel_props[] = {
-       POWER_SUPPLY_PROP_CHARGE_TYPE,
-       POWER_SUPPLY_PROP_CHARGING_ENABLED,
-       POWER_SUPPLY_PROP_PIN_ENABLED,
-       POWER_SUPPLY_PROP_INPUT_SUSPEND,
-       POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
-       POWER_SUPPLY_PROP_VOLTAGE_MAX,
-       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_PARALLEL_MODE,
        POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
        POWER_SUPPLY_PROP_SET_SHIP_MODE,
-       POWER_SUPPLY_PROP_CHARGER_TEMP,
-       POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
 };
 
 static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -633,6 +583,14 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
                else
                        val->intval = 0;
                break;
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+               if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+               || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
+                       rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+                               &val->intval);
+               else
+                       val->intval = 0;
+               break;
        case POWER_SUPPLY_PROP_VOLTAGE_MAX:
                rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
                break;
@@ -640,46 +598,28 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
                rc = smblib_get_charge_param(chg, &chg->param.fcc,
                                             &val->intval);
                break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               rc = smblib_get_prop_slave_current_now(chg, val);
+               break;
+       case POWER_SUPPLY_PROP_CHARGER_TEMP:
+               rc = smb138x_get_prop_charger_temp(chip, val);
+               break;
+       case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+               rc = smblib_get_prop_charger_temp_max(chg, val);
+               break;
        case POWER_SUPPLY_PROP_MODEL_NAME:
-               val->strval = chip->name;
+               val->strval = "smb138x";
                break;
        case POWER_SUPPLY_PROP_PARALLEL_MODE:
                val->intval = chip->dt.pl_mode;
                break;
        case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
-               if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
-                       val->intval = smb138x_get_prop_connector_health(chip);
-               else
-                       val->intval = smb1355_get_prop_connector_health(chip);
+               val->intval = smb138x_get_prop_connector_health(chip);
                break;
        case POWER_SUPPLY_PROP_SET_SHIP_MODE:
                /* Not in ship mode as long as device is active */
                val->intval = 0;
                break;
-       case POWER_SUPPLY_PROP_CHARGER_TEMP:
-               if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
-                       rc = smb138x_get_prop_charger_temp(chip, val);
-               else
-                       rc = smblib_get_prop_charger_temp(chg, val);
-               break;
-       case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
-               rc = smblib_get_prop_charger_temp_max(chg, val);
-               break;
-       case POWER_SUPPLY_PROP_CURRENT_NOW:
-               if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
-                       rc = smblib_get_prop_slave_current_now(chg, val);
-               else
-                       rc = -ENODATA;
-               break;
-       case POWER_SUPPLY_PROP_CURRENT_MAX:
-               if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
-                 && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
-                 || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)))
-                       rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
-                               &val->intval);
-               else
-                       rc = -ENODATA;
-               break;
        default:
                pr_err("parallel power supply get prop %d not supported\n",
                        prop);
@@ -763,7 +703,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy,
        return 0;
 }
 
-static struct power_supply_desc parallel_psy_desc = {
+static const struct power_supply_desc parallel_psy_desc = {
        .name                   = "parallel",
        .type                   = POWER_SUPPLY_TYPE_PARALLEL,
        .properties             = smb138x_parallel_props,
@@ -791,28 +731,6 @@ static int smb138x_init_parallel_psy(struct smb138x *chip)
        return 0;
 }
 
-static int smb1355_init_parallel_psy(struct smb138x *chip)
-{
-       struct power_supply_config parallel_cfg = {};
-       struct smb_charger *chg = &chip->chg;
-
-       parallel_cfg.drv_data = chip;
-       parallel_cfg.of_node = chg->dev->of_node;
-
-       /* change to smb1355's property list */
-       parallel_psy_desc.properties = smb1355_parallel_props;
-       parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props);
-       chip->parallel_psy = devm_power_supply_register(chg->dev,
-                                                  &parallel_psy_desc,
-                                                  &parallel_cfg);
-       if (IS_ERR(chip->parallel_psy)) {
-               pr_err("Couldn't register parallel power supply\n");
-               return PTR_ERR(chip->parallel_psy);
-       }
-
-       return 0;
-}
-
 /******************************
  * VBUS REGULATOR REGISTRATION *
  ******************************/
@@ -1132,6 +1050,7 @@ static int smb138x_init_hw(struct smb138x *chip)
 
 static int smb138x_setup_wa_flags(struct smb138x *chip)
 {
+       struct pmic_revid_data *pmic_rev_id;
        struct device_node *revid_dev_node;
 
        revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
@@ -1141,8 +1060,8 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
                return -EINVAL;
        }
 
-       chip->pmic_rev_id = get_revid_data(revid_dev_node);
-       if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+       pmic_rev_id = get_revid_data(revid_dev_node);
+       if (IS_ERR_OR_NULL(pmic_rev_id)) {
                /*
                 * the revid peripheral must be registered, any failure
                 * here only indicates that the rev-id module has not
@@ -1151,14 +1070,14 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
                return -EPROBE_DEFER;
        }
 
-       switch (chip->pmic_rev_id->pmic_subtype) {
+       switch (pmic_rev_id->pmic_subtype) {
        case SMB1381_SUBTYPE:
-               if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
+               if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
                        chip->wa_flags |= OOB_COMP_WA_BIT;
                break;
        default:
                pr_err("PMIC subtype %d not supported\n",
-                               chip->pmic_rev_id->pmic_subtype);
+                               pmic_rev_id->pmic_subtype);
                return -EINVAL;
        }
 
@@ -1456,7 +1375,6 @@ static int smb138x_master_probe(struct smb138x *chip)
 
        chg->param = v1_params;
 
-       chip->name = "smb1381";
        rc = smblib_init(chg);
        if (rc < 0) {
                pr_err("Couldn't initialize smblib rc=%d\n", rc);
@@ -1517,7 +1435,7 @@ static int smb138x_master_probe(struct smb138x *chip)
        return rc;
 }
 
-static int smb1355_slave_probe(struct smb138x *chip)
+static int smb138x_slave_probe(struct smb138x *chip)
 {
        struct smb_charger *chg = &chip->chg;
        int rc = 0;
@@ -1530,55 +1448,6 @@ static int smb1355_slave_probe(struct smb138x *chip)
                goto cleanup;
        }
 
-       rc = smb138x_parse_dt(chip);
-       if (rc < 0) {
-               pr_err("Couldn't parse device tree rc=%d\n", rc);
-               goto cleanup;
-       }
-
-       rc = smb138x_init_slave_hw(chip);
-       if (rc < 0) {
-               pr_err("Couldn't initialize hardware rc=%d\n", rc);
-               goto cleanup;
-       }
-
-       rc = smb1355_init_parallel_psy(chip);
-       if (rc < 0) {
-               pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
-               goto cleanup;
-       }
-
-       rc = smb138x_determine_initial_slave_status(chip);
-       if (rc < 0) {
-               pr_err("Couldn't determine initial status rc=%d\n", rc);
-               goto cleanup;
-       }
-
-       rc = smb138x_request_interrupts(chip);
-       if (rc < 0) {
-               pr_err("Couldn't request interrupts rc=%d\n", rc);
-               goto cleanup;
-       }
-
-       return 0;
-
-cleanup:
-       smblib_deinit(chg);
-       return rc;
-}
-
-static int smb1381_slave_probe(struct smb138x *chip)
-{
-       struct smb_charger *chg = &chip->chg;
-       int rc = 0;
-
-       chg->param = v1_params;
-
-       rc = smblib_init(chg);
-       if (rc < 0) {
-               pr_err("Couldn't initialize smblib rc=%d\n", rc);
-               goto cleanup;
-       }
        chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
        if (IS_ERR(chg->iio.temp_max_chan)) {
                rc = PTR_ERR(chg->iio.temp_max_chan);
@@ -1646,71 +1515,25 @@ static int smb1381_slave_probe(struct smb138x *chip)
                goto cleanup;
        }
 
-       return 0;
+       return rc;
 
 cleanup:
        smblib_deinit(chg);
+       if (chip->parallel_psy)
+               power_supply_unregister(chip->parallel_psy);
+       if (chg->vbus_vreg && chg->vbus_vreg->rdev)
+               regulator_unregister(chg->vbus_vreg->rdev);
        return rc;
 }
 
-static int slave_probe(struct smb138x *chip)
-{
-       struct device_node *revid_dev_node;
-       int rc = 0;
-
-       revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
-                                       "qcom,pmic-revid", 0);
-       if (!revid_dev_node) {
-               pr_err("Missing qcom,pmic-revid property\n");
-               return -EINVAL;
-       }
-
-       chip->pmic_rev_id = get_revid_data(revid_dev_node);
-       if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
-               /*
-                * the revid peripheral must be registered, any failure
-                * here only indicates that the rev-id module has not
-                * probed yet.
-                */
-               return -EPROBE_DEFER;
-       }
-
-       switch (chip->pmic_rev_id->pmic_subtype) {
-       case SMB1355_SUBTYPE:
-               chip->name = "smb1355";
-               rc = smb1355_slave_probe(chip);
-               break;
-       case SMB1381_SUBTYPE:
-               chip->name = "smb1381";
-               rc = smb1381_slave_probe(chip);
-               break;
-       default:
-               pr_err("Unsupported pmic subtype = 0x%02x\n",
-                               chip->pmic_rev_id->pmic_subtype);
-               rc = -EINVAL;
-       }
-
-       if (rc < 0) {
-               if (rc != -EPROBE_DEFER)
-                       pr_err("Couldn't probe SMB138X rc=%d\n", rc);
-               return rc;
-       }
-
-       return 0;
-}
-
 static const struct of_device_id match_table[] = {
        {
-               .compatible     = "qcom,smb138x-charger",
-               .data           = (void *) PARALLEL_MASTER,
-       },
-       {
-               .compatible     = "qcom,smb138x-parallel-slave",
-               .data           = (void *) PARALLEL_SLAVE,
+               .compatible = "qcom,smb138x-charger",
+               .data = (void *) PARALLEL_MASTER
        },
        {
-               .compatible     = "qcom,smb1355-parallel-slave",
-               .data           = (void *) PARALLEL_SLAVE,
+               .compatible = "qcom,smb138x-parallel-slave",
+               .data = (void *) PARALLEL_SLAVE
        },
        { },
 };
@@ -1757,7 +1580,7 @@ static int smb138x_probe(struct platform_device *pdev)
                rc = smb138x_master_probe(chip);
                break;
        case PARALLEL_SLAVE:
-               rc = slave_probe(chip);
+               rc = smb138x_slave_probe(chip);
                break;
        default:
                pr_err("Couldn't find a matching mode %d\n", chip->chg.mode);
@@ -1771,8 +1594,7 @@ static int smb138x_probe(struct platform_device *pdev)
                goto cleanup;
        }
 
-       pr_info("%s probed successfully mode=%d pl_mode = %d\n",
-               chip->name, chip->chg.mode, chip->dt.pl_mode);
+       pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
        return rc;
 
 cleanup:
index e5ba631..88956d3 100644 (file)
@@ -472,6 +472,15 @@ config REGULATOR_MT6397
          This driver supports the control of different power rails of device
          through regulator interface.
 
+config REGULATOR_ONSEMI_NCP6335D
+       tristate "OnSemi NCP6335D regulator support"
+       depends on I2C
+       help
+        This driver supports the OnSemi NCP6335D switching voltage regulator
+        (buck converter). The regulator is controlled using an I2C interface
+        and supports a programmable voltage range from 0.6V to 1.4V in steps
+        of 6.25mV.
+
 config REGULATOR_PALMAS
        tristate "TI Palmas PMIC Regulators"
        depends on MFD_PALMAS
index 20cf304..e345f10 100644 (file)
@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MT6397)        += mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
+obj-$(CONFIG_REGULATOR_ONSEMI_NCP6335D) += onsemi-ncp6335d.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
diff --git a/drivers/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c
new file mode 100644 (file)
index 0000000..3b4ca4f
--- /dev/null
@@ -0,0 +1,775 @@
+/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/debugfs.h>
+#include <linux/regulator/onsemi-ncp6335d.h>
+#include <linux/string.h>
+
+/* registers */
+#define REG_NCP6335D_PID               0x03
+#define REG_NCP6335D_PROGVSEL1         0x10
+#define REG_NCP6335D_PROGVSEL0         0x11
+#define REG_NCP6335D_PGOOD             0x12
+#define REG_NCP6335D_TIMING            0x13
+#define REG_NCP6335D_COMMAND           0x14
+
+/* constraints */
+#define NCP6335D_MIN_VOLTAGE_UV                600000
+#define NCP6335D_STEP_VOLTAGE_UV       6250
+#define NCP6335D_VOLTAGE_STEPS         128
+#define NCP6335D_MIN_SLEW_NS           166
+#define NCP6335D_MAX_SLEW_NS           1333
+
+/* bits */
+#define NCP6335D_ENABLE                        BIT(7)
+#define NCP6335D_DVS_PWM_MODE          BIT(5)
+#define NCP6335D_PWM_MODE1             BIT(6)
+#define NCP6335D_PWM_MODE0             BIT(7)
+#define NCP6335D_PGOOD_DISCHG          BIT(4)
+#define NCP6335D_SLEEP_MODE            BIT(4)
+
+#define NCP6335D_VOUT_SEL_MASK         0x7F
+#define NCP6335D_SLEW_MASK             0x18
+#define NCP6335D_SLEW_SHIFT            0x3
+
+struct ncp6335d_info {
+       struct regulator_dev *regulator;
+       struct regulator_init_data *init_data;
+       struct regmap *regmap;
+       struct device *dev;
+       unsigned int vsel_reg;
+       unsigned int vsel_backup_reg;
+       unsigned int mode_bit;
+       int curr_voltage;
+       int slew_rate;
+
+       unsigned int step_size;
+       unsigned int min_voltage;
+       unsigned int min_slew_ns;
+       unsigned int max_slew_ns;
+       unsigned int peek_poke_address;
+
+       struct dentry *debug_root;
+};
+
+static int delay_array[] = {10, 20, 30, 40, 50};
+
+static int ncp6335x_read(struct ncp6335d_info *dd, unsigned int reg,
+                                               unsigned int *val)
+{
+       int i = 0, rc = 0;
+
+       rc = regmap_read(dd->regmap, reg, val);
+       for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
+               pr_debug("Failed reading reg=%u - retry(%d)\n", reg, i);
+               msleep(delay_array[i]);
+               rc = regmap_read(dd->regmap, reg, val);
+       }
+
+       if (rc)
+               pr_err("Failed reading reg=%u rc=%d\n", reg, rc);
+
+       return rc;
+}
+
+static int ncp6335x_write(struct ncp6335d_info *dd, unsigned int reg,
+                                               unsigned int val)
+{
+       int i = 0, rc = 0;
+
+       rc = regmap_write(dd->regmap, reg, val);
+       for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
+               pr_debug("Failed writing reg=%u - retry(%d)\n", reg, i);
+               msleep(delay_array[i]);
+               rc = regmap_write(dd->regmap, reg, val);
+       }
+
+       if (rc)
+               pr_err("Failed writing reg=%u rc=%d\n", reg, rc);
+
+       return rc;
+}
+
+static int ncp6335x_update_bits(struct ncp6335d_info *dd, unsigned int reg,
+                                       unsigned int mask, unsigned int val)
+{
+       int i = 0, rc = 0;
+
+       rc = regmap_update_bits(dd->regmap, reg, mask, val);
+       for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
+               pr_debug("Failed updating reg=%u- retry(%d)\n", reg, i);
+               msleep(delay_array[i]);
+               rc = regmap_update_bits(dd->regmap, reg, mask, val);
+       }
+
+       if (rc)
+               pr_err("Failed updating reg=%u rc=%d\n", reg, rc);
+
+       return rc;
+}
+
+static void dump_registers(struct ncp6335d_info *dd,
+                       unsigned int reg, const char *func)
+{
+       unsigned int val = 0;
+
+       ncp6335x_read(dd, reg, &val);
+       dev_dbg(dd->dev, "%s: NCP6335D: Reg = %x, Val = %x\n", func, reg, val);
+}
+
+static void ncp633d_slew_delay(struct ncp6335d_info *dd,
+                                       int prev_uV, int new_uV)
+{
+       u8 val;
+       int delay;
+
+       val = abs(prev_uV - new_uV) / dd->step_size;
+       delay = ((val * dd->slew_rate) / 1000) + 1;
+
+       dev_dbg(dd->dev, "Slew Delay = %d\n", delay);
+
+       udelay(delay);
+}
+
+static int ncp6335d_is_enabled(struct regulator_dev *rdev)
+{
+       int rc, val = 0;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       rc = ncp6335x_read(dd, dd->vsel_reg, &val);
+       if (rc)
+               dev_err(dd->dev, "Unable to read enable register rc(%d)", rc);
+
+       dump_registers(dd, dd->vsel_reg, __func__);
+
+       return ((val & NCP6335D_ENABLE) ? 1 : 0);
+}
+
+static int ncp6335d_enable(struct regulator_dev *rdev)
+{
+       int rc;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       rc = ncp6335x_update_bits(dd, dd->vsel_reg,
+                       NCP6335D_ENABLE, NCP6335D_ENABLE);
+       if (rc)
+               dev_err(dd->dev, "Unable to enable regualtor rc(%d)", rc);
+
+       dump_registers(dd, dd->vsel_reg, __func__);
+
+       return rc;
+}
+
+static int ncp6335d_disable(struct regulator_dev *rdev)
+{
+       int rc;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       rc = ncp6335x_update_bits(dd, dd->vsel_reg,
+                                       NCP6335D_ENABLE, 0);
+       if (rc)
+               dev_err(dd->dev, "Unable to disable regualtor rc(%d)", rc);
+
+       dump_registers(dd, dd->vsel_reg, __func__);
+
+       return rc;
+}
+
+static int ncp6335d_get_voltage(struct regulator_dev *rdev)
+{
+       unsigned int val;
+       int rc;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       rc = ncp6335x_read(dd, dd->vsel_reg, &val);
+       if (rc) {
+               dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
+               return rc;
+       }
+       dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) * dd->step_size) +
+                               dd->min_voltage;
+
+       dump_registers(dd, dd->vsel_reg, __func__);
+
+       return dd->curr_voltage;
+}
+
+static int ncp6335d_set_voltage(struct regulator_dev *rdev,
+                       int min_uV, int max_uV, unsigned *selector)
+{
+       int rc, set_val, new_uV;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size);
+       new_uV = (set_val * dd->step_size) + dd->min_voltage;
+       if (new_uV > max_uV) {
+               dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
+                                                       min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       rc = ncp6335x_update_bits(dd, dd->vsel_reg,
+               NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK));
+       if (rc) {
+               dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
+                                                       min_uV, max_uV);
+       } else {
+               ncp633d_slew_delay(dd, dd->curr_voltage, new_uV);
+               dd->curr_voltage = new_uV;
+       }
+
+       dump_registers(dd, dd->vsel_reg, __func__);
+
+       return rc;
+}
+
+static int ncp6335d_list_voltage(struct regulator_dev *rdev,
+                                       unsigned selector)
+{
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       if (selector >= NCP6335D_VOLTAGE_STEPS)
+               return 0;
+
+       return selector * dd->step_size + dd->min_voltage;
+}
+
+static int ncp6335d_set_mode(struct regulator_dev *rdev,
+                                       unsigned int mode)
+{
+       int rc;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       /* only FAST and NORMAL mode types are supported */
+       if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL) {
+               dev_err(dd->dev, "Mode %d not supported\n", mode);
+               return -EINVAL;
+       }
+
+       rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND, dd->mode_bit,
+                       (mode == REGULATOR_MODE_FAST) ? dd->mode_bit : 0);
+       if (rc) {
+               dev_err(dd->dev, "Unable to set operating mode rc(%d)", rc);
+               return rc;
+       }
+
+       rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND,
+                                       NCP6335D_DVS_PWM_MODE,
+                                       (mode == REGULATOR_MODE_FAST) ?
+                                       NCP6335D_DVS_PWM_MODE : 0);
+       if (rc)
+               dev_err(dd->dev, "Unable to set DVS trans. mode rc(%d)", rc);
+
+       dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
+
+       return rc;
+}
+
+static unsigned int ncp6335d_get_mode(struct regulator_dev *rdev)
+{
+       unsigned int val;
+       int rc;
+       struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+       rc = ncp6335x_read(dd, REG_NCP6335D_COMMAND, &val);
+       if (rc) {
+               dev_err(dd->dev, "Unable to get regulator mode rc(%d)\n", rc);
+               return rc;
+       }
+
+       dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
+
+       if (val & dd->mode_bit)
+               return REGULATOR_MODE_FAST;
+
+       return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops ncp6335d_ops = {
+       .set_voltage = ncp6335d_set_voltage,
+       .get_voltage = ncp6335d_get_voltage,
+       .list_voltage = ncp6335d_list_voltage,
+       .is_enabled = ncp6335d_is_enabled,
+       .enable = ncp6335d_enable,
+       .disable = ncp6335d_disable,
+       .set_mode = ncp6335d_set_mode,
+       .get_mode = ncp6335d_get_mode,
+};
+
+static struct regulator_desc rdesc = {
+       .name = "ncp6335d",
+       .supply_name = "vin",
+       .owner = THIS_MODULE,
+       .n_voltages = NCP6335D_VOLTAGE_STEPS,
+       .ops = &ncp6335d_ops,
+};
+
+static int ncp6335d_restore_working_reg(struct device_node *node,
+                                       struct ncp6335d_info *dd)
+{
+       int ret;
+       unsigned int val;
+
+       /* Restore register from back up register */
+       ret = ncp6335x_read(dd, dd->vsel_backup_reg, &val);
+       if (ret < 0) {
+               dev_err(dd->dev, "Failed to get backup data from reg %d, ret = %d\n",
+                       dd->vsel_backup_reg, ret);
+               return ret;
+       }
+
+       ret = ncp6335x_update_bits(dd, dd->vsel_reg,
+                                       NCP6335D_VOUT_SEL_MASK, val);
+       if (ret < 0) {
+               dev_err(dd->dev, "Failed to update working reg %d, ret = %d\n",
+                       dd->vsel_reg,  ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ncp6335d_parse_gpio(struct device_node *node,
+                                       struct ncp6335d_info *dd)
+{
+       int ret = 0, gpio;
+       enum of_gpio_flags flags;
+
+       if (!of_find_property(node, "onnn,vsel-gpio", NULL))
+               return ret;
+
+       /* Get GPIO connected to vsel and set its output */
+       gpio = of_get_named_gpio_flags(node,
+                       "onnn,vsel-gpio", 0, &flags);
+       if (!gpio_is_valid(gpio)) {
+               if (gpio != -EPROBE_DEFER)
+                       dev_err(dd->dev, "Could not get vsel, ret = %d\n",
+                               gpio);
+               return gpio;
+       }
+
+       ret = devm_gpio_request(dd->dev, gpio, "ncp6335d_vsel");
+       if (ret) {
+               dev_err(dd->dev, "Failed to obtain gpio %d ret = %d\n",
+                               gpio, ret);
+                       return ret;
+       }
+
+       ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ? 0 : 1);
+       if (ret) {
+               dev_err(dd->dev, "Failed to set GPIO %d to: %s, ret = %d",
+                               gpio, flags & OF_GPIO_ACTIVE_LOW ?
+                               "GPIO_LOW" : "GPIO_HIGH", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ncp6335d_init(struct i2c_client *client, struct ncp6335d_info *dd,
+                       const struct ncp6335d_platform_data *pdata)
+{
+       int rc;
+       unsigned int val;
+
+       switch (pdata->default_vsel) {
+       case NCP6335D_VSEL0:
+               dd->vsel_reg = REG_NCP6335D_PROGVSEL0;
+               dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL1;
+               dd->mode_bit = NCP6335D_PWM_MODE0;
+       break;
+       case NCP6335D_VSEL1:
+               dd->vsel_reg = REG_NCP6335D_PROGVSEL1;
+               dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL0;
+               dd->mode_bit = NCP6335D_PWM_MODE1;
+       break;
+       default:
+               dev_err(dd->dev, "Invalid VSEL ID %d\n", pdata->default_vsel);
+               return -EINVAL;
+       }
+
+       if (of_property_read_bool(client->dev.of_node, "onnn,restore-reg")) {
+               rc = ncp6335d_restore_working_reg(client->dev.of_node, dd);
+               if (rc)
+                       return rc;
+       }
+
+       rc = ncp6335d_parse_gpio(client->dev.of_node, dd);
+       if (rc)
+               return rc;
+
+       /* get the current programmed voltage */
+       rc = ncp6335x_read(dd, dd->vsel_reg, &val);
+       if (rc) {
+               dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
+               return rc;
+       }
+       dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
+                               dd->step_size) + dd->min_voltage;
+
+       /* set discharge */
+       rc = ncp6335x_update_bits(dd, REG_NCP6335D_PGOOD,
+                                       NCP6335D_PGOOD_DISCHG,
+                                       (pdata->discharge_enable ?
+                                       NCP6335D_PGOOD_DISCHG : 0));
+       if (rc) {
+               dev_err(dd->dev, "Unable to set Active Discharge rc(%d)\n", rc);
+               return -EINVAL;
+       }
+
+       /* set slew rate */
+       if (pdata->slew_rate_ns < dd->min_slew_ns ||
+                       pdata->slew_rate_ns > dd->max_slew_ns) {
+               dev_err(dd->dev, "Invalid slew rate %d\n", pdata->slew_rate_ns);
+               return -EINVAL;
+       }
+
+       dd->slew_rate = pdata->slew_rate_ns;
+       val = DIV_ROUND_UP(pdata->slew_rate_ns, dd->min_slew_ns);
+       val = ilog2(val);
+
+       rc = ncp6335x_update_bits(dd, REG_NCP6335D_TIMING,
+                       NCP6335D_SLEW_MASK, val << NCP6335D_SLEW_SHIFT);
+       if (rc)
+               dev_err(dd->dev, "Unable to set slew rate rc(%d)\n", rc);
+
+       /* Set Sleep mode bit */
+       rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND,
+                               NCP6335D_SLEEP_MODE, pdata->sleep_enable ?
+                                               NCP6335D_SLEEP_MODE : 0);
+       if (rc)
+               dev_err(dd->dev, "Unable to set sleep mode (%d)\n", rc);
+
+       dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
+       dump_registers(dd, REG_NCP6335D_PROGVSEL0, __func__);
+       dump_registers(dd, REG_NCP6335D_TIMING, __func__);
+       dump_registers(dd, REG_NCP6335D_PGOOD, __func__);
+
+       return rc;
+}
+
+static struct regmap_config ncp6335d_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int ncp6335d_parse_dt(struct i2c_client *client,
+                               struct ncp6335d_info *dd)
+{
+       int rc;
+
+       rc = of_property_read_u32(client->dev.of_node,
+                       "onnn,step-size", &dd->step_size);
+       if (rc < 0) {
+               dev_err(&client->dev, "step size missing: rc = %d.\n", rc);
+               return rc;
+       }
+
+       rc = of_property_read_u32(client->dev.of_node,
+                       "onnn,min-slew-ns", &dd->min_slew_ns);
+       if (rc < 0) {
+               dev_err(&client->dev, "min slew us missing: rc = %d.\n", rc);
+               return rc;
+       }
+
+       rc = of_property_read_u32(client->dev.of_node,
+                       "onnn,max-slew-ns", &dd->max_slew_ns);
+       if (rc < 0) {
+               dev_err(&client->dev, "max slew us missing: rc = %d.\n", rc);
+               return rc;
+       }
+
+       rc = of_property_read_u32(client->dev.of_node,
+                       "onnn,min-setpoint", &dd->min_voltage);
+       if (rc < 0) {
+               dev_err(&client->dev, "min set point missing: rc = %d.\n", rc);
+               return rc;
+       }
+
+       return rc;
+}
+
+static struct ncp6335d_platform_data *
+       ncp6335d_get_of_platform_data(struct i2c_client *client)
+{
+       struct ncp6335d_platform_data *pdata = NULL;
+       struct regulator_init_data *init_data;
+       const char *mode_name;
+       int rc;
+
+       init_data = of_get_regulator_init_data(&client->dev,
+                               client->dev.of_node, &rdesc);
+       if (!init_data) {
+               dev_err(&client->dev, "regulator init data is missing\n");
+               return pdata;
+       }
+
+       pdata = devm_kzalloc(&client->dev,
+                       sizeof(struct ncp6335d_platform_data), GFP_KERNEL);
+       if (!pdata)
+               return pdata;
+
+       rc = of_property_read_u32(client->dev.of_node,
+                       "onnn,vsel", &pdata->default_vsel);
+       if (rc < 0) {
+               dev_err(&client->dev, "onnn,vsel property missing: rc = %d.\n",
+                       rc);
+               return NULL;
+       }
+
+       rc = of_property_read_u32(client->dev.of_node,
+                       "onnn,slew-ns", &pdata->slew_rate_ns);
+       if (rc < 0) {
+               dev_err(&client->dev, "onnn,slew-ns property missing: rc = %d.\n",
+                       rc);
+               return NULL;
+       }
+
+       pdata->discharge_enable = of_property_read_bool(client->dev.of_node,
+                                               "onnn,discharge-enable");
+
+       pdata->sleep_enable = of_property_read_bool(client->dev.of_node,
+                                               "onnn,sleep-enable");
+
+       pdata->init_data = init_data;
+
+       init_data->constraints.input_uV = init_data->constraints.max_uV;
+       init_data->constraints.valid_ops_mask =
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_STATUS |
+                               REGULATOR_CHANGE_MODE;
+       init_data->constraints.valid_modes_mask =
+                               REGULATOR_MODE_NORMAL |
+                               REGULATOR_MODE_FAST;
+
+       rc = of_property_read_string(client->dev.of_node, "onnn,mode",
+                                       &mode_name);
+       if (!rc) {
+               if (strcmp("pwm", mode_name) == 0) {
+                       init_data->constraints.initial_mode =
+                                                       REGULATOR_MODE_FAST;
+               } else if (strcmp("auto", mode_name) == 0) {
+                       init_data->constraints.initial_mode =
+                                                       REGULATOR_MODE_NORMAL;
+               } else {
+                       dev_err(&client->dev, "onnn,mode, unknown regulator mode: %s\n",
+                               mode_name);
+                       return NULL;
+               }
+       }
+
+       return pdata;
+}
+
+static int get_reg(void *data, u64 *val)
+{
+       struct ncp6335d_info *dd = data;
+       int rc;
+       unsigned int temp = 0;
+
+       rc = ncp6335x_read(dd, dd->peek_poke_address, &temp);
+       if (rc < 0)
+               dev_err(dd->dev, "Couldn't read reg %x rc = %d\n",
+                               dd->peek_poke_address, rc);
+       else
+               *val = temp;
+
+       return rc;
+}
+
+static int set_reg(void *data, u64 val)
+{
+       struct ncp6335d_info *dd = data;
+       int rc;
+       unsigned int temp = 0;
+
+       temp = (unsigned int) val;
+       rc = ncp6335x_write(dd, dd->peek_poke_address, temp);
+       if (rc < 0)
+               dev_err(dd->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n",
+                       dd->peek_poke_address, temp, rc);
+
+       return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n");
+
+static int ncp6335d_regulator_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       int rc;
+       unsigned int val = 0;
+       struct ncp6335d_info *dd;
+       const struct ncp6335d_platform_data *pdata;
+       struct regulator_config config = { };
+
+       if (client->dev.of_node)
+               pdata = ncp6335d_get_of_platform_data(client);
+       else
+               pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&client->dev, "Platform data not specified\n");
+               return -EINVAL;
+       }
+
+       dd = devm_kzalloc(&client->dev, sizeof(*dd), GFP_KERNEL);
+       if (!dd)
+               return -ENOMEM;
+
+       if (client->dev.of_node) {
+               rc = ncp6335d_parse_dt(client, dd);
+               if (rc)
+                       return rc;
+       } else {
+               dd->step_size   = NCP6335D_STEP_VOLTAGE_UV;
+               dd->min_voltage = NCP6335D_MIN_VOLTAGE_UV;
+               dd->min_slew_ns = NCP6335D_MIN_SLEW_NS;
+               dd->max_slew_ns = NCP6335D_MAX_SLEW_NS;
+       }
+
+       dd->regmap = devm_regmap_init_i2c(client, &ncp6335d_regmap_config);
+       if (IS_ERR(dd->regmap)) {
+               dev_err(&client->dev, "Error allocating regmap\n");
+               return PTR_ERR(dd->regmap);
+       }
+
+       rc = ncp6335x_read(dd, REG_NCP6335D_PID, &val);
+       if (rc) {
+               dev_err(&client->dev, "Unable to identify NCP6335D, rc(%d)\n",
+                                                                       rc);
+               return rc;
+       }
+       dev_info(&client->dev, "Detected Regulator NCP6335D PID = %d\n", val);
+
+       dd->init_data = pdata->init_data;
+       dd->dev = &client->dev;
+       i2c_set_clientdata(client, dd);
+
+       rc = ncp6335d_init(client, dd, pdata);
+       if (rc) {
+               dev_err(&client->dev, "Unable to initialize the regulator\n");
+               return -EINVAL;
+       }
+
+       config.dev = &client->dev;
+       config.init_data = dd->init_data;
+       config.regmap = dd->regmap;
+       config.driver_data = dd;
+       config.of_node = client->dev.of_node;
+
+       dd->regulator = regulator_register(&rdesc, &config);
+
+       if (IS_ERR(dd->regulator)) {
+               dev_err(&client->dev, "Unable to register regulator rc(%ld)",
+                                               PTR_ERR(dd->regulator));
+
+               return PTR_ERR(dd->regulator);
+       }
+
+       dd->debug_root = debugfs_create_dir("ncp6335x", NULL);
+       if (!dd->debug_root)
+               dev_err(&client->dev, "Couldn't create debug dir\n");
+
+       if (dd->debug_root) {
+               struct dentry *ent;
+
+               ent = debugfs_create_x32("address", S_IFREG | S_IWUSR | S_IRUGO,
+                                         dd->debug_root,
+                                         &(dd->peek_poke_address));
+               if (!ent)
+                       dev_err(&client->dev, "Couldn't create address debug file rc = %d\n",
+                                                                       rc);
+
+               ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO,
+                                         dd->debug_root, dd,
+                                         &poke_poke_debug_ops);
+               if (!ent)
+                       dev_err(&client->dev, "Couldn't create data debug file rc = %d\n",
+                                                                       rc);
+       }
+
+       return 0;
+}
+
+static int ncp6335d_regulator_remove(struct i2c_client *client)
+{
+       struct ncp6335d_info *dd = i2c_get_clientdata(client);
+
+       regulator_unregister(dd->regulator);
+
+       debugfs_remove_recursive(dd->debug_root);
+
+       return 0;
+}
+
+static const struct of_device_id ncp6335d_match_table[] = {
+       { .compatible = "onnn,ncp6335d-regulator", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ncp6335d_match_table);
+
+static const struct i2c_device_id ncp6335d_id[] = {
+       {"ncp6335d", -1},
+       { },
+};
+
+static struct i2c_driver ncp6335d_regulator_driver = {
+       .driver = {
+               .name = "ncp6335d-regulator",
+               .owner = THIS_MODULE,
+               .of_match_table = ncp6335d_match_table,
+       },
+       .probe = ncp6335d_regulator_probe,
+       .remove = ncp6335d_regulator_remove,
+       .id_table = ncp6335d_id,
+};
+
+/**
+ * ncp6335d_regulator_init() - initialized ncp6335d regulator driver
+ * This function registers the ncp6335d regulator platform driver.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init ncp6335d_regulator_init(void)
+{
+       static bool initialized;
+
+       if (initialized)
+               return 0;
+
+       initialized = true;
+
+       return i2c_add_driver(&ncp6335d_regulator_driver);
+}
+EXPORT_SYMBOL(ncp6335d_regulator_init);
+subsys_initcall(ncp6335d_regulator_init);
+
+static void __exit ncp6335d_regulator_exit(void)
+{
+       i2c_del_driver(&ncp6335d_regulator_driver);
+}
+module_exit(ncp6335d_regulator_exit);
+MODULE_DESCRIPTION("OnSemi-NCP6335D regulator driver");
+MODULE_LICENSE("GPL v2");
index f40afdd..00662dd 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/bitrev.h>
 #include <linux/bcd.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #define S35390A_CMD_STATUS1    0
 #define S35390A_CMD_STATUS2    1
 #define S35390A_ALRM_BYTE_HOURS        1
 #define S35390A_ALRM_BYTE_MINS 2
 
+/* flags for STATUS1 */
 #define S35390A_FLAG_POC       0x01
 #define S35390A_FLAG_BLD       0x02
+#define S35390A_FLAG_INT2      0x04
 #define S35390A_FLAG_24H       0x40
 #define S35390A_FLAG_RESET     0x80
+
+/* flag for STATUS2 */
 #define S35390A_FLAG_TEST      0x01
 
 #define S35390A_INT2_MODE_MASK         0xF0
@@ -94,19 +99,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
        return 0;
 }
 
-static int s35390a_reset(struct s35390a *s35390a)
+/*
+ * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
+ * To keep the information if an irq is pending, pass the value read from
+ * STATUS1 to the caller.
+ */
+static int s35390a_reset(struct s35390a *s35390a, char *status1)
 {
-       char buf[1];
-
-       if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
-               return -EIO;
-
-       if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
+       char buf;
+       int ret;
+       unsigned initcount = 0;
+
+       ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
+       if (ret < 0)
+               return ret;
+
+       if (*status1 & S35390A_FLAG_POC)
+               /*
+                * Do not communicate for 0.5 seconds since the power-on
+                * detection circuit is in operation.
+                */
+               msleep(500);
+       else if (!(*status1 & S35390A_FLAG_BLD))
+               /*
+                * If both POC and BLD are unset everything is fine.
+                */
                return 0;
 
-       buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
-       buf[0] &= 0xf0;
-       return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
+       /*
+        * At least one of POC and BLD are set, so reinitialise chip. Keeping
+        * this information in the hardware to know later that the time isn't
+        * valid is unfortunately not possible because POC and BLD are cleared
+        * on read. So the reset is best done now.
+        *
+        * The 24H bit is kept over reset, so set it already here.
+        */
+initialize:
+       *status1 = S35390A_FLAG_24H;
+       buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
+       ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
+
+       if (ret < 0)
+               return ret;
+
+       ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
+       if (ret < 0)
+               return ret;
+
+       if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
+               /* Try up to five times to reset the chip */
+               if (initcount < 5) {
+                       ++initcount;
+                       goto initialize;
+               } else
+                       return -EIO;
+       }
+
+       return 1;
 }
 
 static int s35390a_disable_test_mode(struct s35390a *s35390a)
@@ -242,6 +291,8 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
 
        if (alm->time.tm_wday != -1)
                buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
+       else
+               buf[S35390A_ALRM_BYTE_WDAY] = 0;
 
        buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
                        alm->time.tm_hour) | 0x80;
@@ -265,27 +316,61 @@ static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
        char buf[3], sts;
        int i, err;
 
+       /*
+        * initialize all members to -1 to signal the core that they are not
+        * defined by the hardware.
+        */
+       alm->time.tm_sec = -1;
+       alm->time.tm_min = -1;
+       alm->time.tm_hour = -1;
+       alm->time.tm_mday = -1;
+       alm->time.tm_mon = -1;
+       alm->time.tm_year = -1;
+       alm->time.tm_wday = -1;
+       alm->time.tm_yday = -1;
+       alm->time.tm_isdst = -1;
+
        err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
        if (err < 0)
                return err;
 
-       if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
-               return -EINVAL;
+       if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
+               /*
+                * When the alarm isn't enabled, the register to configure
+                * the alarm time isn't accessible.
+                */
+               alm->enabled = 0;
+               return 0;
+       } else {
+               alm->enabled = 1;
+       }
 
        err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
        if (err < 0)
                return err;
 
        /* This chip returns the bits of each byte in reverse order */
-       for (i = 0; i < 3; ++i) {
+       for (i = 0; i < 3; ++i)
                buf[i] = bitrev8(buf[i]);
-               buf[i] &= ~0x80;
-       }
 
-       alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
-       alm->time.tm_hour = s35390a_reg2hr(s35390a,
-                                               buf[S35390A_ALRM_BYTE_HOURS]);
-       alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
+       /*
+        * B0 of the three matching registers is an enable flag. Iff it is set
+        * the configured value is used for matching.
+        */
+       if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
+               alm->time.tm_wday =
+                       bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
+
+       if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
+               alm->time.tm_hour =
+                       s35390a_reg2hr(s35390a,
+                                      buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
+
+       if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
+               alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
+
+       /* alarm triggers always at s=0 */
+       alm->time.tm_sec = 0;
 
        dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
                        __func__, alm->time.tm_min, alm->time.tm_hour,
@@ -327,11 +412,11 @@ static struct i2c_driver s35390a_driver;
 static int s35390a_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       int err;
+       int err, err_reset;
        unsigned int i;
        struct s35390a *s35390a;
        struct rtc_time tm;
-       char buf[1];
+       char buf, status1;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
@@ -360,29 +445,35 @@ static int s35390a_probe(struct i2c_client *client,
                }
        }
 
-       err = s35390a_reset(s35390a);
-       if (err < 0) {
+       err_reset = s35390a_reset(s35390a, &status1);
+       if (err_reset < 0) {
+               err = err_reset;
                dev_err(&client->dev, "error resetting chip\n");
                goto exit_dummy;
        }
 
-       err = s35390a_disable_test_mode(s35390a);
-       if (err < 0) {
-               dev_err(&client->dev, "error disabling test mode\n");
-               goto exit_dummy;
-       }
-
-       err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
-       if (err < 0) {
-               dev_err(&client->dev, "error checking 12/24 hour mode\n");
-               goto exit_dummy;
-       }
-       if (buf[0] & S35390A_FLAG_24H)
+       if (status1 & S35390A_FLAG_24H)
                s35390a->twentyfourhour = 1;
        else
                s35390a->twentyfourhour = 0;
 
-       if (s35390a_get_datetime(client, &tm) < 0)
+       if (status1 & S35390A_FLAG_INT2) {
+               /* disable alarm (and maybe test mode) */
+               buf = 0;
+               err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
+               if (err < 0) {
+                       dev_err(&client->dev, "error disabling alarm");
+                       goto exit_dummy;
+               }
+       } else {
+               err = s35390a_disable_test_mode(s35390a);
+               if (err < 0) {
+                       dev_err(&client->dev, "error disabling test mode\n");
+                       goto exit_dummy;
+               }
+       }
+
+       if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
                dev_warn(&client->dev, "clock needs to be set\n");
 
        device_set_wakeup_capable(&client->dev, 1);
@@ -395,6 +486,10 @@ static int s35390a_probe(struct i2c_client *client,
                err = PTR_ERR(s35390a->rtc);
                goto exit_dummy;
        }
+
+       if (status1 & S35390A_FLAG_INT2)
+               rtc_update_irq(s35390a->rtc, 1, RTC_AF);
+
        return 0;
 
 exit_dummy:
index 60232bd..71216aa 100644 (file)
@@ -18,6 +18,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 #include <linux/kernel.h>
+#include <linux/clk.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -59,6 +60,7 @@ struct tegra_rtc_info {
        struct platform_device  *pdev;
        struct rtc_device       *rtc_dev;
        void __iomem            *rtc_base; /* NULL if not initialized. */
+       struct clk              *clk;
        int                     tegra_rtc_irq; /* alarm and periodic irq */
        spinlock_t              tegra_rtc_lock;
 };
@@ -332,6 +334,14 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
        if (info->tegra_rtc_irq <= 0)
                return -EBUSY;
 
+       info->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(info->clk))
+               return PTR_ERR(info->clk);
+
+       ret = clk_prepare_enable(info->clk);
+       if (ret < 0)
+               return ret;
+
        /* set context info. */
        info->pdev = pdev;
        spin_lock_init(&info->tegra_rtc_lock);
@@ -352,7 +362,7 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
                ret = PTR_ERR(info->rtc_dev);
                dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
                        ret);
-               return ret;
+               goto disable_clk;
        }
 
        ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
@@ -362,12 +372,25 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Unable to request interrupt for device (err=%d).\n",
                        ret);
-               return ret;
+               goto disable_clk;
        }
 
        dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
 
        return 0;
+
+disable_clk:
+       clk_disable_unprepare(info->clk);
+       return ret;
+}
+
+static int tegra_rtc_remove(struct platform_device *pdev)
+{
+       struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(info->clk);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -419,6 +442,7 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
 
 MODULE_ALIAS("platform:tegra_rtc");
 static struct platform_driver tegra_rtc_driver = {
+       .remove         = tegra_rtc_remove,
        .shutdown       = tegra_rtc_shutdown,
        .driver         = {
                .name   = "tegra_rtc",
index 9c706d8..6f5e272 100644 (file)
@@ -218,7 +218,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
                task->num_scatter = qc->n_elem;
        } else {
                for_each_sg(qc->sg, sg, qc->n_elem, si)
-                       xfer += sg->length;
+                       xfer += sg_dma_len(sg);
 
                task->total_xfer_len = xfer;
                task->num_scatter = si;
index 92648a5..63f5965 100644 (file)
@@ -390,6 +390,7 @@ struct MPT3SAS_TARGET {
  * @eedp_enable: eedp support enable bit
  * @eedp_type: 0(type_1), 1(type_2), 2(type_3)
  * @eedp_block_length: block size
+ * @ata_command_pending: SATL passthrough outstanding for device
  */
 struct MPT3SAS_DEVICE {
        struct MPT3SAS_TARGET *sas_target;
@@ -398,6 +399,17 @@ struct MPT3SAS_DEVICE {
        u8      configured_lun;
        u8      block;
        u8      tlr_snoop_check;
+       /*
+        * Bug workaround for SATL handling: the mpt2/3sas firmware
+        * doesn't return BUSY or TASK_SET_FULL for subsequent
+        * commands while a SATL pass through is in operation as the
+        * spec requires, it simply does nothing with them until the
+        * pass through completes, causing them possibly to timeout if
+        * the passthrough is a long executing command (like format or
+        * secure erase).  This variable allows us to do the right
+        * thing while a SATL command is pending.
+        */
+       unsigned long ata_command_pending;
 };
 
 #define MPT3_CMD_NOT_USED      0x8000  /* free */
index f6a8e99..8a5fbdb 100644 (file)
@@ -3707,9 +3707,18 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
        }
 }
 
-static inline bool ata_12_16_cmd(struct scsi_cmnd *scmd)
+static int _scsih_set_satl_pending(struct scsi_cmnd *scmd, bool pending)
 {
-       return (scmd->cmnd[0] == ATA_12 || scmd->cmnd[0] == ATA_16);
+       struct MPT3SAS_DEVICE *priv = scmd->device->hostdata;
+
+       if (scmd->cmnd[0] != ATA_12 && scmd->cmnd[0] != ATA_16)
+               return 0;
+
+       if (pending)
+               return test_and_set_bit(0, &priv->ata_command_pending);
+
+       clear_bit(0, &priv->ata_command_pending);
+       return 0;
 }
 
 /**
@@ -3733,9 +3742,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc)
                if (!scmd)
                        continue;
                count++;
-               if (ata_12_16_cmd(scmd))
-                       scsi_internal_device_unblock(scmd->device,
-                                                       SDEV_RUNNING);
+               _scsih_set_satl_pending(scmd, false);
                mpt3sas_base_free_smid(ioc, smid);
                scsi_dma_unmap(scmd);
                if (ioc->pci_error_recovery)
@@ -3866,13 +3873,6 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
        if (ioc->logging_level & MPT_DEBUG_SCSI)
                scsi_print_command(scmd);
 
-       /*
-        * Lock the device for any subsequent command until command is
-        * done.
-        */
-       if (ata_12_16_cmd(scmd))
-               scsi_internal_device_block(scmd->device);
-
        sas_device_priv_data = scmd->device->hostdata;
        if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
                scmd->result = DID_NO_CONNECT << 16;
@@ -3886,6 +3886,19 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
                return 0;
        }
 
+       /*
+        * Bug work around for firmware SATL handling.  The loop
+        * is based on atomic operations and ensures consistency
+        * since we're lockless at this point
+        */
+       do {
+               if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
+                       scmd->result = SAM_STAT_BUSY;
+                       scmd->scsi_done(scmd);
+                       return 0;
+               }
+       } while (_scsih_set_satl_pending(scmd, true));
+
        sas_target_priv_data = sas_device_priv_data->sas_target;
 
        /* invalid device handle */
@@ -4445,8 +4458,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        if (scmd == NULL)
                return 1;
 
-       if (ata_12_16_cmd(scmd))
-               scsi_internal_device_unblock(scmd->device, SDEV_RUNNING);
+       _scsih_set_satl_pending(scmd, false);
 
        mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
 
index 5d81bcc..9b3af78 100644 (file)
@@ -1995,6 +1995,22 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
 
 #define READ_CAPACITY_RETRIES_ON_RESET 10
 
+/*
+ * Ensure that we don't overflow sector_t when CONFIG_LBDAF is not set
+ * and the reported logical block size is bigger than 512 bytes. Note
+ * that last_sector is a u64 and therefore logical_to_sectors() is not
+ * applicable.
+ */
+static bool sd_addressable_capacity(u64 lba, unsigned int sector_size)
+{
+       u64 last_sector = (lba + 1ULL) << (ilog2(sector_size) - 9);
+
+       if (sizeof(sector_t) == 4 && last_sector > U32_MAX)
+               return false;
+
+       return true;
+}
+
 static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                                                unsigned char *buffer)
 {
@@ -2060,7 +2076,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                return -ENODEV;
        }
 
-       if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) {
+       if (!sd_addressable_capacity(lba, sector_size)) {
                sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
                        "kernel compiled with support for large block "
                        "devices.\n");
@@ -2146,7 +2162,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
                return sector_size;
        }
 
-       if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) {
+       if (!sd_addressable_capacity(lba, sector_size)) {
                sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
                        "kernel compiled with support for large block "
                        "devices.\n");
@@ -2810,7 +2826,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
                rw_max = q->limits.io_opt =
                        sdkp->opt_xfer_blocks * sdp->sector_size;
        else
-               rw_max = BLK_DEF_MAX_SECTORS;
+               rw_max = min_not_zero(logical_to_sectors(sdp, dev_max),
+                                     (sector_t)BLK_DEF_MAX_SECTORS);
 
        /* Combine with controller limits */
        q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
index 93a523b..29d8c74 100644 (file)
@@ -1008,6 +1008,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
                result = get_user(val, ip);
                if (result)
                        return result;
+               if (val > SG_MAX_CDB_SIZE)
+                       return -ENOMEM;
                sfp->next_cmd_len = (val > 0) ? val : 0;
                return 0;
        case SG_GET_VERSION_NUM:
index 64c8674..804586a 100644 (file)
@@ -834,6 +834,7 @@ static void get_capabilities(struct scsi_cd *cd)
        unsigned char *buffer;
        struct scsi_mode_data data;
        struct scsi_sense_hdr sshdr;
+       unsigned int ms_len = 128;
        int rc, n;
 
        static const char *loadmech[] =
@@ -860,10 +861,11 @@ static void get_capabilities(struct scsi_cd *cd)
        scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
 
        /* ask for mode page 0x2a */
-       rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
+       rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len,
                             SR_TIMEOUT, 3, &data, NULL);
 
-       if (!scsi_status_is_good(rc)) {
+       if (!scsi_status_is_good(rc) || data.length > ms_len ||
+           data.header_length + data.block_descriptor_length > data.length) {
                /* failed, drive doesn't have capabilities mode page */
                cd->cdi.speed = 1;
                cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
index 34b0adb..ea008ff 100644 (file)
@@ -367,6 +367,14 @@ config MSM_SPM
          driver allows configuring SPM to allow different low power modes for
          both core and L2.
 
+config MSM_L2_SPM
+       bool "SPM support for L2 cache"
+       help
+         Enable SPM driver support for L2 cache. Some MSM chipsets allow
+         control of L2 cache low power mode with a Subsystem Power manager.
+         Enabling this driver allows configuring L2 SPM for low power modes
+         on supported chipsets
+
 config QCOM_SCM
        bool "Secure Channel Manager (SCM) support"
        default n
@@ -573,6 +581,16 @@ config MSM_BOOT_STATS
         This figures are reported in mpm sleep clock cycles and have a
         resolution of 31 bits as 1 bit is used as an overflow check.
 
+config MSM_BOOT_TIME_MARKER
+       bool "Use MSM boot time marker reporting"
+       depends on MSM_BOOT_STATS
+       help
+        Use this to mark msm boot kpi for measurement.
+        An instrumentation for boot time measurement.
+        To create an entry, call "place_marker" function.
+        At userspace, write marker name to "/sys/kernel/debug/bootkpi/kpi_values"
+        If unsure, say N
+
 config QCOM_CPUSS_DUMP
     bool "CPU Subsystem Dumping support"
     help
@@ -900,4 +918,28 @@ config QCOM_CX_IPEAK
          clients are going to cross their thresholds then Cx ipeak hw module will raise
          an interrupt to cDSP block to throttle cDSP fmax.
 
+config MSM_CACHE_M4M_ERP64
+       bool "Cache and M4M error report"
+       depends on ARCH_MSM8996
+       help
+         Say 'Y' here to enable reporting of cache and M4M errors to the kernel
+         log. The kernel log contains collected error syndrome and address
+         registers. These register dumps can be used as useful information
+         to find out possible hardware problems.
+
+config MSM_CACHE_M4M_ERP64_PANIC_ON_CE
+       bool "Panic on correctable cache/M4M errors"
+       help
+         Say 'Y' here to cause kernel panic when correctable cache/M4M errors
+         are detected.  Enabling this is useful when you want to dump memory
+         and system state close to the time when the error occured.
+
+          If unsure, say N.
+
+config MSM_CACHE_M4M_ERP64_PANIC_ON_UE
+       bool "Panic on uncorrectable cache/M4M errors"
+       help
+         Say 'Y' here to cause kernel panic when uncorrectable cache/M4M errors
+         are detected.
+
 source "drivers/soc/qcom/memshare/Kconfig"
index 87698b7..5eeede2 100644 (file)
@@ -86,6 +86,7 @@ obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o
 obj-$(CONFIG_MSM_GLADIATOR_HANG_DETECT) += gladiator_hang_detect.o
 obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
 obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o
+obj-$(CONFIG_MSM_BOOT_TIME_MARKER) += boot_marker.o
 obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
 ifdef CONFIG_ARCH_MSM8996
 obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_kryo.o
@@ -104,3 +105,4 @@ obj-$(CONFIG_WCD_DSP_GLINK) += wcd-dsp-glink.o
 obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
 obj-$(CONFIG_QCOM_EARLY_RANDOM)        += early_random.o
 obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o
+obj-$(CONFIG_MSM_CACHE_M4M_ERP64) += cache_m4m_erp64.o
diff --git a/drivers/soc/qcom/boot_marker.c b/drivers/soc/qcom/boot_marker.c
new file mode 100644 (file)
index 0000000..b3a6c9f
--- /dev/null
@@ -0,0 +1,183 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <soc/qcom/boot_stats.h>
+
+#define MAX_STRING_LEN 256
+#define BOOT_MARKER_MAX_LEN 40
+static struct dentry *dent_bkpi, *dent_bkpi_status;
+static struct boot_marker boot_marker_list;
+
+struct boot_marker {
+       char marker_name[BOOT_MARKER_MAX_LEN];
+       unsigned long long int timer_value;
+       struct list_head list;
+       struct mutex lock;
+};
+
+static void _create_boot_marker(const char *name,
+                                       unsigned long long int timer_value)
+{
+       struct boot_marker *new_boot_marker;
+
+       pr_debug("%-41s:%llu.%03llu seconds\n", name,
+               timer_value/TIMER_KHZ,
+               ((timer_value % TIMER_KHZ)
+               * 1000) / TIMER_KHZ);
+
+       new_boot_marker = kmalloc(sizeof(*new_boot_marker), GFP_KERNEL);
+       if (!new_boot_marker)
+               return;
+
+       strlcpy(new_boot_marker->marker_name, name,
+               sizeof(new_boot_marker->marker_name));
+       new_boot_marker->timer_value = timer_value;
+
+       mutex_lock(&boot_marker_list.lock);
+       list_add_tail(&(new_boot_marker->list), &(boot_marker_list.list));
+       mutex_unlock(&boot_marker_list.lock);
+}
+
+static void set_bootloader_stats(void)
+{
+       _create_boot_marker("M - APPSBL Start - ",
+               readl_relaxed(&boot_stats->bootloader_start));
+       _create_boot_marker("M - APPSBL Display Init - ",
+               readl_relaxed(&boot_stats->bootloader_display));
+       _create_boot_marker("M - APPSBL Early-Domain Start - ",
+               readl_relaxed(&boot_stats->bootloader_early_domain_start));
+       _create_boot_marker("D - APPSBL Kernel Load Time - ",
+               readl_relaxed(&boot_stats->bootloader_load_kernel));
+       _create_boot_marker("D - APPSBL Kernel Auth Time - ",
+               readl_relaxed(&boot_stats->bootloader_checksum));
+       _create_boot_marker("M - APPSBL End - ",
+               readl_relaxed(&boot_stats->bootloader_end));
+}
+
+void place_marker(const char *name)
+{
+       _create_boot_marker((char *) name, msm_timer_get_sclk_ticks());
+}
+EXPORT_SYMBOL(place_marker);
+
+static ssize_t bootkpi_reader(struct file *fp, char __user *user_buffer,
+                       size_t count, loff_t *position)
+{
+       int rc = 0;
+       char *buf;
+       int temp = 0;
+       struct boot_marker *marker;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       mutex_lock(&boot_marker_list.lock);
+       list_for_each_entry(marker, &boot_marker_list.list, list) {
+               temp += scnprintf(buf + temp, PAGE_SIZE - temp,
+                       "%-41s:%llu.%03llu seconds\n",
+                       marker->marker_name,
+                       marker->timer_value/TIMER_KHZ,
+                       (((marker->timer_value % TIMER_KHZ)
+                       * 1000) / TIMER_KHZ));
+       }
+       mutex_unlock(&boot_marker_list.lock);
+       rc = simple_read_from_buffer(user_buffer, count, position, buf, temp);
+       kfree(buf);
+       return rc;
+}
+
+static ssize_t bootkpi_writer(struct file *fp, const char __user *user_buffer,
+                       size_t count, loff_t *position)
+{
+       int rc = 0;
+       char buf[MAX_STRING_LEN];
+
+       if (count > MAX_STRING_LEN)
+               return -EINVAL;
+       rc = simple_write_to_buffer(buf,
+               sizeof(buf) - 1, position, user_buffer, count);
+       if (rc < 0)
+               return rc;
+       buf[rc] = '\0';
+       place_marker(buf);
+       return rc;
+}
+
+static int bootkpi_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static const struct file_operations fops_bkpi = {
+       .owner = THIS_MODULE,
+       .open  = bootkpi_open,
+       .read  = bootkpi_reader,
+       .write = bootkpi_writer,
+};
+
+static int __init init_bootkpi(void)
+{
+       dent_bkpi = debugfs_create_dir("bootkpi", NULL);
+       if (IS_ERR_OR_NULL(dent_bkpi))
+               return -ENODEV;
+
+       dent_bkpi_status = debugfs_create_file("kpi_values",
+               (S_IRUGO|S_IWUGO), dent_bkpi, 0, &fops_bkpi);
+       if (IS_ERR_OR_NULL(dent_bkpi_status)) {
+               debugfs_remove(dent_bkpi);
+               dent_bkpi = NULL;
+               pr_err("boot_marker: Could not create 'kpi_values' debugfs file\n");
+               return -ENODEV;
+       }
+
+       INIT_LIST_HEAD(&boot_marker_list.list);
+       mutex_init(&boot_marker_list.lock);
+       set_bootloader_stats();
+       return 0;
+}
+subsys_initcall(init_bootkpi);
+
+static void __exit exit_bootkpi(void)
+{
+       struct boot_marker *marker;
+       struct boot_marker *temp_addr;
+
+       debugfs_remove_recursive(dent_bkpi);
+       mutex_lock(&boot_marker_list.lock);
+       list_for_each_entry_safe(marker, temp_addr, &boot_marker_list.list,
+                                       list) {
+               list_del(&marker->list);
+               kfree(marker);
+       }
+       mutex_unlock(&boot_marker_list.lock);
+       boot_stats_exit();
+}
+module_exit(exit_bootkpi);
+
+MODULE_DESCRIPTION("MSM boot key performance indicators");
+MODULE_LICENSE("GPL v2");
index 2fc9cbf..eb5357e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014,2016, 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
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/sched.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-
-struct boot_stats {
-       uint32_t bootloader_start;
-       uint32_t bootloader_end;
-       uint32_t bootloader_display;
-       uint32_t bootloader_load_kernel;
-};
+#include <linux/export.h>
+#include <linux/types.h>
+#include <soc/qcom/boot_stats.h>
 
 static void __iomem *mpm_counter_base;
 static uint32_t mpm_counter_freq;
-static struct boot_stats __iomem *boot_stats;
+struct boot_stats __iomem *boot_stats;
 
 static int mpm_parse_dt(void)
 {
@@ -88,6 +85,42 @@ static void print_boot_stats(void)
                mpm_counter_freq);
 }
 
+unsigned long long int msm_timer_get_sclk_ticks(void)
+{
+       unsigned long long int t1, t2;
+       int loop_count = 10;
+       int loop_zero_count = 3;
+       int tmp = USEC_PER_SEC;
+       void __iomem *sclk_tick;
+
+       do_div(tmp, TIMER_KHZ);
+       tmp /= (loop_zero_count-1);
+       sclk_tick = mpm_counter_base;
+       if (!sclk_tick)
+               return -EINVAL;
+       while (loop_zero_count--) {
+               t1 = __raw_readl_no_log(sclk_tick);
+               do {
+                       udelay(1);
+                       t2 = t1;
+                       t1 = __raw_readl_no_log(sclk_tick);
+               } while ((t2 != t1) && --loop_count);
+               if (!loop_count) {
+                       pr_err("boot_stats: SCLK  did not stabilize\n");
+                       return 0;
+               }
+               if (t1)
+                       break;
+
+               udelay(tmp);
+       }
+       if (!loop_zero_count) {
+               pr_err("boot_stats: SCLK reads zero\n");
+               return 0;
+       }
+       return t1;
+}
+
 int boot_stats_init(void)
 {
        int ret;
@@ -98,9 +131,14 @@ int boot_stats_init(void)
 
        print_boot_stats();
 
+       if (!(boot_marker_enabled()))
+               boot_stats_exit();
+       return 0;
+}
+
+int boot_stats_exit(void)
+{
        iounmap(boot_stats);
        iounmap(mpm_counter_base);
-
        return 0;
 }
-
diff --git a/drivers/soc/qcom/cache_m4m_erp64.c b/drivers/soc/qcom/cache_m4m_erp64.c
new file mode 100644 (file)
index 0000000..758e9d0
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "msm_cache_erp64: " fmt
+
+#include <linux/printk.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/cpu.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/cpu_pm.h>
+#include <linux/smp.h>
+
+#include <soc/qcom/kryo-l2-accessors.h>
+
+/* Instruction cache */
+#define ICECR_EL1                      S3_1_c11_c1_0
+#define        ICECR_IRQ_EN                    (BIT(1) | BIT(3) | BIT(5) | BIT(7))
+#define ICESR_EL1                      S3_1_c11_c1_1
+#define        ICESR_BIT_L1DPE                 BIT(3)
+#define        ICESR_BIT_L1TPE                 BIT(2)
+#define        ICESR_BIT_L0DPE                 BIT(1)
+#define        ICESR_BIT_L0TPE                 BIT(0)
+#define ICESYNR0_EL1                   S3_1_c11_c1_3
+#define ICESYNR1_EL1                   S3_1_c11_c1_4
+#define ICEAR0_EL1                     S3_1_c11_c1_5
+#define ICEAR1_EL1                     S3_1_c11_c1_6
+#define ICESRS_EL1                     S3_1_c11_c1_2
+
+/* Data cache */
+#define DCECR_EL1                      S3_1_c11_c5_0
+#define        DCECR_IRQ_EN                    (BIT(1) | BIT(3) | BIT(5) | BIT(7) | \
+                                        BIT(9))
+#define DCESR_EL1                      S3_1_c11_c5_1
+#define        DCESR_BIT_S1FTLBDPE             BIT(4)
+#define        DCESR_BIT_S1FTLBTPE             BIT(3)
+#define        DCESR_BIT_L1DPE                 BIT(2)
+#define        DCESR_BIT_L1PTPE                BIT(1)
+#define        DCESR_BIT_L1VTPE                BIT(0)
+#define DCESYNR0_EL1                   S3_1_c11_c5_3
+#define DCESYNR1_EL1                   S3_1_c11_c5_4
+#define DCESRS_EL1                     S3_1_c11_c5_2
+#define DCEAR0_EL1                     S3_1_c11_c5_5
+#define DCEAR1_EL1                     S3_1_c11_c5_6
+
+/* L2 cache */
+#define L2CPUSRSELR_EL1I               S3_3_c15_c0_6
+#define L2CPUSRDR_EL1                  S3_3_c15_c0_7
+#define L2ECR0_IA                      0x200
+#define        L2ECR0_IRQ_EN                   (BIT(1) | BIT(3) | BIT(6) | BIT(9) | \
+                                       BIT(11) | BIT(13) | BIT(16) | \
+                                       BIT(19) | BIT(21) | BIT(23) | \
+                                       BIT(26) | BIT(29))
+
+#define L2ECR1_IA                      0x201
+#define        L2ECR1_IRQ_EN                   (BIT(1) | BIT(3) | BIT(6) | BIT(9) | \
+                                       BIT(11) | BIT(13) | BIT(16) | \
+                                       BIT(19) | BIT(21) | BIT(23) | BIT(29))
+#define L2ECR2_IA                      0x202
+#define L2ECR2_IRQ_EN_MASK             0x3FFFFFF
+#define L2ECR2_IRQ_EN                  (BIT(1) | BIT(3) | BIT(6) | BIT(9) | \
+                                       BIT(12) | BIT(15) | BIT(17) | \
+                                       BIT(19) | BIT(22) | BIT(25))
+#define L2ESR0_IA                      0x204
+#define L2ESR0_MASK                    0x00FFFFFF
+#define L2ESR0_CE                      ((BIT(0) | BIT(1) | BIT(2) | BIT(3) | \
+                                       BIT(4) | BIT(5) | BIT(12) | BIT(13) | \
+                                       BIT(14) | BIT(15) | BIT(16) | BIT(17)) \
+                                       & L2ESR0_MASK)
+#define L2ESR0_UE                      (~L2ESR0_CE & L2ESR0_MASK)
+#define L2ESRS0_IA                     0x205
+#define L2ESR1_IA                      0x206
+#define L2ESR1_MASK                    0x80FFFBFF
+#define L2ESRS1_IA                     0x207
+#define L2ESYNR0_IA                    0x208
+#define L2ESYNR1_IA                    0x209
+#define L2ESYNR2_IA                    0x20A
+#define L2ESYNR3_IA                    0x20B
+#define L2ESYNR4_IA                    0x20C
+#define L2EAR0_IA                      0x20E
+#define L2EAR1_IA                      0x20F
+
+#define L3_QLL_HML3_FIRA               0x3000
+#define L3_QLL_HML3_FIRA_CE            (BIT(1) | BIT(3) | BIT(5))
+#define L3_QLL_HML3_FIRA_UE            (BIT(2) | BIT(4) | BIT(6))
+#define L3_QLL_HML3_FIRAC              0x3008
+#define L3_QLL_HML3_FIRAS              0x3010
+#define L3_QLL_HML3_FIRAT0C            0x3020
+#define L3_QLL_HML3_FIRAT0C_IRQ_EN     0xFFFFFFFF
+#define L3_QLL_HML3_FIRAT1C            0x3024
+#define L3_QLL_HML3_FIRAT1S            0x302C
+#define L3_QLL_HML3_FIRAT1S_IRQ_EN     0x01EFC8FE
+#define L3_QLL_HML3_FIRSYNA            0x3100
+#define L3_QLL_HML3_FIRSYNB            0x3104
+#define L3_QLL_HML3_FIRSYNC            0x3108
+#define L3_QLL_HML3_FIRSYND            0x310C
+
+#define M4M_ERR_STATUS                 0x10000
+#define M4M_ERR_STATUS_MASK            0x1FF
+#define M4M_ERR_Q22SIB_RET_DEC_ERR     (BIT(7))
+#define M4M_ERR_Q22SIB_RET_SLV_ERR     (BIT(6))
+#define M4M_ERR_CLR                    0x10008
+#define M4M_INT_CTRL                   0x10010
+#define M4M_INT_CTRL_IRQ_EN            0x1FF
+#define M4M_ERR_CTRL                   0x10018
+#define M4M_ERR_INJ                    0x10020
+#define M4M_ERR_CAP_0                  0x10030
+#define M4M_ERR_CAP_1                  0x10038
+#define M4M_ERR_CAP_2                  0x10040
+#define M4M_ERR_CAP_3                  0x10048
+
+#define AFFINITY_LEVEL_L3              3
+
+#ifdef CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE
+static bool __read_mostly panic_on_ce = true;
+#else
+static bool __read_mostly panic_on_ce;
+#endif
+
+#ifdef CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE
+static bool __read_mostly panic_on_ue = true;
+#else
+static bool __read_mostly panic_on_ue;
+#endif
+
+module_param(panic_on_ce, bool, false);
+module_param(panic_on_ue, bool, false);
+
+static void __iomem *hml3_base;
+static void __iomem *m4m_base;
+
+enum erp_irq_index { IRQ_L1, IRQ_L2_INFO0, IRQ_L2_INFO1, IRQ_L2_ERR0,
+                    IRQ_L2_ERR1, IRQ_L3, IRQ_M4M, IRQ_MAX };
+static const char * const erp_irq_names[] = {
+       "l1_irq", "l2_irq_info_0", "l2_irq_info_1", "l2_irq_err_0",
+       "l2_irq_err_1", "l3_irq", "m4m_irq"
+};
+static int erp_irqs[IRQ_MAX];
+
+struct msm_l1_err_stats {
+       /* nothing */
+};
+
+static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats);
+static DEFINE_PER_CPU(struct call_single_data, handler_csd);
+
+#define erp_mrs(reg) ({                                                        \
+       u64 __val;                                                      \
+       asm volatile("mrs %0, " __stringify(reg) : "=r" (__val));       \
+       __val;                                                          \
+})
+
+#define erp_msr(reg, val) {                                        \
+       asm volatile("msr " __stringify(reg) ", %0" : : "r" (val)); \
+}
+
+static void msm_erp_show_icache_error(void)
+{
+       u64 icesr;
+       int cpu = raw_smp_processor_id();
+
+       icesr = erp_mrs(ICESR_EL1);
+       if (!(icesr & (ICESR_BIT_L0TPE | ICESR_BIT_L0DPE | ICESR_BIT_L1TPE |
+                      ICESR_BIT_L1DPE))) {
+               pr_debug("CPU%d: No I-cache error detected ICESR 0x%llx\n",
+                        cpu, icesr);
+               goto clear_out;
+       }
+
+       pr_alert("CPU%d: I-cache error\n", cpu);
+       pr_alert("CPU%d: ICESR_EL1 0x%llx ICESYNR0 0x%llx ICESYNR1 0x%llx ICEAR0 0x%llx IECAR1 0x%llx\n",
+                cpu, icesr, erp_mrs(ICESYNR0_EL1), erp_mrs(ICESYNR1_EL1),
+                erp_mrs(ICEAR0_EL1), erp_mrs(ICEAR1_EL1));
+
+       /*
+        * all detectable I-cache erros are recoverable as
+        * corrupted lines are refetched
+        */
+       if (panic_on_ce)
+               BUG_ON(1);
+       else
+               WARN_ON(1);
+
+clear_out:
+       erp_msr(ICESR_EL1, icesr);
+}
+
+static void msm_erp_show_dcache_error(void)
+{
+       u64 dcesr;
+       int cpu = raw_smp_processor_id();
+
+       dcesr = erp_mrs(DCESR_EL1);
+       if (!(dcesr & (DCESR_BIT_L1VTPE | DCESR_BIT_L1PTPE | DCESR_BIT_L1DPE |
+                      DCESR_BIT_S1FTLBTPE | DCESR_BIT_S1FTLBDPE))) {
+               pr_debug("CPU%d: No D-cache error detected DCESR 0x%llx\n",
+                        cpu, dcesr);
+               goto clear_out;
+       }
+
+       pr_alert("CPU%d: D-cache error detected\n", cpu);
+       pr_alert("CPU%d: L1 DCESR 0x%llx, DCESYNR0 0x%llx, DCESYNR1 0x%llx, DCEAR0 0x%llx, DCEAR1 0x%llx\n",
+               cpu, dcesr, erp_mrs(DCESYNR0_EL1), erp_mrs(DCESYNR1_EL1),
+               erp_mrs(DCEAR0_EL1), erp_mrs(DCEAR1_EL1));
+
+       /* all D-cache erros are correctable */
+       if (panic_on_ce)
+               BUG_ON(1);
+       else
+               WARN_ON(1);
+
+clear_out:
+       erp_msr(DCESR_EL1, dcesr);
+}
+
+static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
+{
+       msm_erp_show_icache_error();
+       msm_erp_show_dcache_error();
+       return IRQ_HANDLED;
+}
+
+static DEFINE_SPINLOCK(local_handler_lock);
+static void msm_l2_erp_local_handler(void *force)
+{
+       unsigned long flags;
+       u64 esr0, esr1;
+       bool parity_ue, parity_ce, misc_ue;
+       int cpu;
+
+       spin_lock_irqsave(&local_handler_lock, flags);
+
+       esr0 = get_l2_indirect_reg(L2ESR0_IA);
+       esr1 = get_l2_indirect_reg(L2ESR1_IA);
+       parity_ue = esr0 & L2ESR0_UE;
+       parity_ce = esr0 & L2ESR0_CE;
+       misc_ue = esr1;
+       cpu = raw_smp_processor_id();
+
+       if (force || parity_ue || parity_ce || misc_ue) {
+               if (parity_ue)
+                       pr_alert("CPU%d: L2 uncorrectable parity error\n", cpu);
+               if (parity_ce)
+                       pr_alert("CPU%d: L2 correctable parity error\n", cpu);
+               if (misc_ue)
+                       pr_alert("CPU%d: L2 (non-parity) error\n", cpu);
+               pr_alert("CPU%d: L2ESR0 0x%llx, L2ESR1 0x%llx\n",
+                       cpu, esr0, esr1);
+               pr_alert("CPU%d: L2ESYNR0 0x%llx, L2ESYNR1 0x%llx, L2ESYNR2 0x%llx\n",
+                       cpu, get_l2_indirect_reg(L2ESYNR0_IA),
+                       get_l2_indirect_reg(L2ESYNR1_IA),
+                       get_l2_indirect_reg(L2ESYNR2_IA));
+               pr_alert("CPU%d: L2EAR0 0x%llx, L2EAR1 0x%llx\n", cpu,
+                       get_l2_indirect_reg(L2EAR0_IA),
+                       get_l2_indirect_reg(L2EAR1_IA));
+       } else {
+               pr_info("CPU%d: No L2 error detected in L2ESR0 0x%llx, L2ESR1 0x%llx)\n",
+                       cpu, esr0, esr1);
+       }
+
+       /* clear */
+       set_l2_indirect_reg(L2ESR0_IA, esr0);
+       set_l2_indirect_reg(L2ESR1_IA, esr1);
+
+       if (panic_on_ue)
+               BUG_ON(parity_ue || misc_ue);
+       else
+               WARN_ON(parity_ue || misc_ue);
+
+       if (panic_on_ce)
+               BUG_ON(parity_ce);
+       else
+               WARN_ON(parity_ce);
+
+       spin_unlock_irqrestore(&local_handler_lock, flags);
+}
+
+static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id)
+{
+       int cpu;
+       struct call_single_data *csd;
+
+       for_each_online_cpu(cpu) {
+               csd = &per_cpu(handler_csd, cpu);
+               csd->func = msm_l2_erp_local_handler;
+               smp_call_function_single_async(cpu, csd);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_l3_erp_irq(int irq, void *dev_id)
+{
+       u32 hml3_fira;
+       bool parity_ue, parity_ce, misc_ue;
+
+       hml3_fira = readl_relaxed(hml3_base + L3_QLL_HML3_FIRA);
+       parity_ue = (hml3_fira & L3_QLL_HML3_FIRAT1S_IRQ_EN) &
+                       L3_QLL_HML3_FIRA_UE;
+       parity_ce = (hml3_fira & L3_QLL_HML3_FIRAT1S_IRQ_EN) &
+                       L3_QLL_HML3_FIRA_CE;
+       misc_ue = (hml3_fira & L3_QLL_HML3_FIRAT1S_IRQ_EN) &
+                       ~(L3_QLL_HML3_FIRA_UE | L3_QLL_HML3_FIRA_CE);
+       if (parity_ue)
+               pr_alert("L3 uncorrectable parity error\n");
+       if (parity_ce)
+               pr_alert("L3 correctable parity error\n");
+       if (misc_ue)
+               pr_alert("L3 (non-parity) error\n");
+
+       pr_alert("HML3_FIRA    0x%0x\n", hml3_fira);
+       pr_alert("HML3_FIRSYNA 0x%0x, HML3_FIRSYNB 0x%0x\n",
+               readl_relaxed(hml3_base + L3_QLL_HML3_FIRSYNA),
+               readl_relaxed(hml3_base + L3_QLL_HML3_FIRSYNB));
+       pr_alert("HML3_FIRSYNC 0x%0x, HML3_FIRSYND 0x%0x\n",
+               readl_relaxed(hml3_base + L3_QLL_HML3_FIRSYNC),
+               readl_relaxed(hml3_base + L3_QLL_HML3_FIRSYND));
+
+       if (panic_on_ue)
+               BUG_ON(parity_ue || misc_ue);
+       else
+               WARN_ON(parity_ue || misc_ue);
+
+       if (panic_on_ce)
+               BUG_ON(parity_ce);
+       else
+               WARN_ON(parity_ce);
+
+       writel_relaxed(hml3_fira, hml3_base + L3_QLL_HML3_FIRAC);
+       /* ensure of irq clear */
+       wmb();
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_m4m_erp_irq(int irq, void *dev_id)
+{
+       u32 m4m_status;
+
+       pr_alert("CPU%d: M4M error detected\n", raw_smp_processor_id());
+       m4m_status = readl_relaxed(m4m_base + M4M_ERR_STATUS);
+       pr_alert("M4M_ERR_STATUS 0x%0x\n", m4m_status);
+       if ((m4m_status & M4M_ERR_STATUS_MASK) &
+           ~(M4M_ERR_Q22SIB_RET_DEC_ERR | M4M_ERR_Q22SIB_RET_SLV_ERR)) {
+               pr_alert("M4M_ERR_CAP_0  0x%0x, M4M_ERR_CAP_1 0x%x\n",
+                        readl_relaxed(m4m_base + M4M_ERR_CAP_0),
+                        readl_relaxed(m4m_base + M4M_ERR_CAP_1));
+               pr_alert("M4M_ERR_CAP_2  0x%0x, M4M_ERR_CAP_3 0x%x\n",
+                        readl_relaxed(m4m_base + M4M_ERR_CAP_2),
+                        readl_relaxed(m4m_base + M4M_ERR_CAP_3));
+       } else {
+               /*
+                * M4M error-capture registers not valid when error detected
+                * due to DEC_ERR or SLV_ERR. L2E registers are still valid.
+                */
+               pr_alert("Omit dumping M4M_ERR_CAP\n");
+       }
+
+       /*
+        * On QSB errors, the L2 captures the bad address and syndrome in
+        * L2E error registers.  Therefore dump L2E always whenever M4M error
+        * detected.
+        */
+       on_each_cpu(msm_l2_erp_local_handler, (void *)1, 1);
+       writel_relaxed(1, m4m_base + M4M_ERR_CLR);
+       /* ensure of irq clear */
+       wmb();
+
+       if (panic_on_ue)
+               BUG_ON(1);
+       else
+               WARN_ON(1);
+
+       return IRQ_HANDLED;
+}
+
+static void enable_erp_irq_callback(void *info)
+{
+       enable_percpu_irq(erp_irqs[IRQ_L1], IRQ_TYPE_NONE);
+}
+
+static void disable_erp_irq_callback(void *info)
+{
+       disable_percpu_irq(erp_irqs[IRQ_L1]);
+}
+
+static void msm_cache_erp_irq_init(void *param)
+{
+       u64 v;
+       /* Enable L0/L1 I/D cache error reporting. */
+       erp_msr(ICECR_EL1, ICECR_IRQ_EN);
+       erp_msr(DCECR_EL1, DCECR_IRQ_EN);
+       /*
+        * Enable L2 data, tag, QSB and possion error reporting.
+        */
+       set_l2_indirect_reg(L2ECR0_IA, L2ECR0_IRQ_EN);
+       set_l2_indirect_reg(L2ECR1_IA, L2ECR1_IRQ_EN);
+       v = (get_l2_indirect_reg(L2ECR2_IA) & ~L2ECR2_IRQ_EN_MASK)
+               | L2ECR2_IRQ_EN;
+       set_l2_indirect_reg(L2ECR2_IA, v);
+}
+
+static void msm_cache_erp_l3_init(void)
+{
+       writel_relaxed(L3_QLL_HML3_FIRAT0C_IRQ_EN,
+                      hml3_base + L3_QLL_HML3_FIRAT0C);
+       writel_relaxed(L3_QLL_HML3_FIRAT1S_IRQ_EN,
+                      hml3_base + L3_QLL_HML3_FIRAT1S);
+}
+
+static int cache_erp_cpu_pm_callback(struct notifier_block *self,
+                                    unsigned long cmd, void *v)
+{
+       unsigned long aff_level = (unsigned long) v;
+
+       switch (cmd) {
+       case CPU_CLUSTER_PM_EXIT:
+               msm_cache_erp_irq_init(NULL);
+
+               if (aff_level >= AFFINITY_LEVEL_L3)
+                       msm_cache_erp_l3_init();
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block cache_erp_cpu_pm_notifier = {
+       .notifier_call = cache_erp_cpu_pm_callback,
+};
+
+static int cache_erp_cpu_callback(struct notifier_block *nfb,
+                                 unsigned long action, void *hcpu)
+{
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_STARTING:
+               msm_cache_erp_irq_init(NULL);
+               enable_erp_irq_callback(NULL);
+               break;
+       case CPU_DYING:
+               disable_erp_irq_callback(NULL);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block cache_erp_cpu_notifier = {
+       .notifier_call = cache_erp_cpu_callback,
+};
+
+static int msm_cache_erp_probe(struct platform_device *pdev)
+{
+       int i, ret = 0;
+       struct resource *r;
+
+       dev_dbg(&pdev->dev, "enter\n");
+
+       /* L3 */
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hml3_base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(hml3_base)) {
+               dev_err(&pdev->dev, "failed to ioremap (0x%pK)\n", hml3_base);
+               return PTR_ERR(hml3_base);
+       }
+
+       for (i = 0; i <= IRQ_L3; i++) {
+               r = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+                                                erp_irq_names[i]);
+               if (!r) {
+                       dev_err(&pdev->dev, "failed to get %s\n",
+                               erp_irq_names[i]);
+                       return -ENODEV;
+               }
+               erp_irqs[i] = r->start;
+       }
+
+       msm_cache_erp_l3_init();
+
+       /* L0/L1 erp irq per cpu */
+       dev_info(&pdev->dev, "Registering for L1 error interrupts\n");
+       ret = request_percpu_irq(erp_irqs[IRQ_L1], msm_l1_erp_irq,
+                                erp_irq_names[IRQ_L1], &msm_l1_erp_stats);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request L0/L1 ERP irq %s (%d)\n",
+                       erp_irq_names[IRQ_L1], ret);
+               return ret;
+       } else {
+               dev_dbg(&pdev->dev, "requested L0/L1 ERP irq %s\n",
+                       erp_irq_names[IRQ_L1]);
+       }
+
+       get_online_cpus();
+       register_hotcpu_notifier(&cache_erp_cpu_notifier);
+       cpu_pm_register_notifier(&cache_erp_cpu_pm_notifier);
+
+       /* Perform L1/L2 cache error detection init on online cpus */
+       on_each_cpu(msm_cache_erp_irq_init, NULL, 1);
+       /* Enable irqs */
+       on_each_cpu(enable_erp_irq_callback, NULL, 1);
+       put_online_cpus();
+
+       /* L2 erp irq per cluster */
+       dev_info(&pdev->dev, "Registering for L2 error interrupts\n");
+       for (i = IRQ_L2_INFO0; i <= IRQ_L2_ERR1; i++) {
+               ret = devm_request_irq(&pdev->dev, erp_irqs[i],
+                                               msm_l2_erp_irq,
+                                               IRQF_ONESHOT |
+                                               IRQF_TRIGGER_HIGH,
+                                               erp_irq_names[i], NULL);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request irq %s (%d)\n",
+                               erp_irq_names[i], ret);
+                       goto cleanup;
+               }
+       }
+
+       /* L3 erp irq */
+       dev_info(&pdev->dev, "Registering for L3 error interrupts\n");
+       ret = devm_request_irq(&pdev->dev, erp_irqs[IRQ_L3], msm_l3_erp_irq,
+                              IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+                              erp_irq_names[IRQ_L3], NULL);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request L3 irq %s (%d)\n",
+                       erp_irq_names[IRQ_L3], ret);
+               goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       free_percpu_irq(erp_irqs[IRQ_L1], NULL);
+       return ret;
+}
+
+static void msm_m4m_erp_irq_init(void)
+{
+       writel_relaxed(M4M_INT_CTRL_IRQ_EN, m4m_base + M4M_INT_CTRL);
+       writel_relaxed(0, m4m_base + M4M_ERR_CTRL);
+}
+
+static int msm_m4m_erp_m4m_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *r;
+
+       dev_dbg(&pdev->dev, "enter\n");
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       m4m_base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(m4m_base)) {
+               dev_err(&pdev->dev, "failed to ioremap (0x%pK)\n", m4m_base);
+               return PTR_ERR(m4m_base);
+       }
+
+       r = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+                                        erp_irq_names[IRQ_M4M]);
+       if (!r) {
+               dev_err(&pdev->dev, "failed to get %s\n",
+                       erp_irq_names[IRQ_M4M]);
+               ret = -ENODEV;
+               goto exit;
+       }
+       erp_irqs[IRQ_M4M] = r->start;
+
+       dev_info(&pdev->dev, "Registering for M4M error interrupts\n");
+       ret = devm_request_irq(&pdev->dev, erp_irqs[IRQ_M4M],
+                                       msm_m4m_erp_irq,
+                                       IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+                                       erp_irq_names[IRQ_M4M], NULL);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request irq %s (%d)\n",
+                       erp_irq_names[IRQ_M4M], ret);
+               goto exit;
+       }
+
+       msm_m4m_erp_irq_init();
+
+exit:
+       return ret;
+}
+
+static struct of_device_id cache_erp_dt_ids[] = {
+       { .compatible = "qcom,kryo_cache_erp64", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, cache_erp_dt_ids);
+
+static struct platform_driver msm_cache_erp_driver = {
+       .probe = msm_cache_erp_probe,
+       .driver = {
+               .name = "msm_cache_erp64",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(cache_erp_dt_ids),
+       },
+};
+
+static struct of_device_id m4m_erp_dt_ids[] = {
+       { .compatible = "qcom,m4m_erp", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, m4m_erp_dt_ids);
+static struct platform_driver msm_m4m_erp_driver = {
+       .probe = msm_m4m_erp_m4m_probe,
+       .driver = {
+               .name = "msm_m4m_erp",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(m4m_erp_dt_ids),
+       },
+};
+
+static int __init msm_cache_erp_init(void)
+{
+       int r;
+
+       r = platform_driver_register(&msm_cache_erp_driver);
+       if (!r)
+               r = platform_driver_register(&msm_m4m_erp_driver);
+       if (r)
+               pr_err("failed to register driver %d\n", r);
+       return r;
+}
+
+arch_initcall(msm_cache_erp_init);
index ab46eb7..8c242bc 100644 (file)
 #include <soc/qcom/socinfo.h>
 #include <soc/qcom/ramdump.h>
 
-#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
-#include <net/cnss_prealloc.h>
-#endif
-
-
 #include "wlan_firmware_service_v01.h"
 
 #ifdef CONFIG_ICNSS_DEBUG
@@ -202,6 +197,7 @@ enum icnss_driver_state {
        ICNSS_MSA0_ASSIGNED,
        ICNSS_WLFW_EXISTS,
        ICNSS_WDOG_BITE,
+       ICNSS_SHUTDOWN_DONE,
 };
 
 struct ce_irq_list {
@@ -695,6 +691,8 @@ static int icnss_qmi_pin_connect_result_ind(void *msg, unsigned int msg_len)
                goto out;
        }
 
+       memset(&ind_msg, 0, sizeof(ind_msg));
+
        ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01;
        ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN;
        ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei;
@@ -1968,8 +1966,6 @@ static int icnss_call_driver_probe(struct icnss_priv *priv)
        if (ret < 0) {
                icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
                             ret, priv->state);
-               wcnss_prealloc_check_memory_leak();
-               wcnss_pre_alloc_reset();
                goto out;
        }
 
@@ -1990,9 +1986,13 @@ static int icnss_call_driver_shutdown(struct icnss_priv *priv)
        if (!priv->ops || !priv->ops->shutdown)
                goto out;
 
+       if (test_bit(ICNSS_SHUTDOWN_DONE, &penv->state))
+               goto out;
+
        icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
 
        priv->ops->shutdown(&priv->pdev->dev);
+       set_bit(ICNSS_SHUTDOWN_DONE, &penv->state);
 
 out:
        return 0;
@@ -2030,6 +2030,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
        }
 
 out:
+       clear_bit(ICNSS_SHUTDOWN_DONE, &penv->state);
        return 0;
 
 call_probe:
@@ -2099,8 +2100,6 @@ static int icnss_driver_event_register_driver(void *data)
        if (ret) {
                icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
                             ret, penv->state);
-               wcnss_prealloc_check_memory_leak();
-               wcnss_pre_alloc_reset();
                goto power_off;
        }
 
@@ -2125,8 +2124,6 @@ static int icnss_driver_event_unregister_driver(void *data)
                penv->ops->remove(&penv->pdev->dev);
 
        clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
-       wcnss_prealloc_check_memory_leak();
-       wcnss_pre_alloc_reset();
 
        penv->ops = NULL;
 
@@ -2151,8 +2148,6 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
        penv->ops->remove(&priv->pdev->dev);
 
        clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
-       wcnss_prealloc_check_memory_leak();
-       wcnss_pre_alloc_reset();
 
        icnss_hw_power_off(penv);
 
@@ -3667,6 +3662,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
                case ICNSS_WDOG_BITE:
                        seq_puts(s, "MODEM WDOG BITE");
                        continue;
+               case ICNSS_SHUTDOWN_DONE:
+                       seq_puts(s, "SHUTDOWN DONE");
+                       continue;
                }
 
                seq_printf(s, "UNKNOWN-%d", i);
index f9d967f..e5f6104 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,7 +22,7 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
-
+#include <linux/spinlock.h>
 
 static int ipc_router_mhi_xprt_debug_mask;
 module_param_named(debug_mask, ipc_router_mhi_xprt_debug_mask,
@@ -123,9 +123,9 @@ struct ipc_router_mhi_xprt {
        struct completion sft_close_complete;
        unsigned xprt_version;
        unsigned xprt_option;
-       struct mutex tx_addr_map_list_lock;
+       spinlock_t tx_addr_map_list_lock;
        struct list_head tx_addr_map_list;
-       struct mutex rx_addr_map_list_lock;
+       spinlock_t rx_addr_map_list_lock;
        struct list_head rx_addr_map_list;
 };
 
@@ -179,16 +179,16 @@ void ipc_router_mhi_release_pkt(struct kref *ref)
  * Return: The mapped virtual Address if found, NULL otherwise.
  */
 void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list,
-                               struct mutex *addr_map_list_lock,
-                               void *addr)
+                               spinlock_t *addr_map_list_lock, void *addr)
 {
        struct ipc_router_mhi_addr_map *addr_mapping;
        struct ipc_router_mhi_addr_map *tmp_addr_mapping;
+       unsigned long flags;
        void *virt_addr;
 
        if (!addr_map_list || !addr_map_list_lock)
                return NULL;
-       mutex_lock(addr_map_list_lock);
+       spin_lock_irqsave(addr_map_list_lock, flags);
        list_for_each_entry_safe(addr_mapping, tmp_addr_mapping,
                                addr_map_list, list_node) {
                if (addr_mapping->virt_addr == addr) {
@@ -198,11 +198,11 @@ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list,
                                kref_put(&addr_mapping->pkt->ref,
                                        ipc_router_mhi_release_pkt);
                        kfree(addr_mapping);
-                       mutex_unlock(addr_map_list_lock);
+                       spin_unlock_irqrestore(addr_map_list_lock, flags);
                        return virt_addr;
                }
        }
-       mutex_unlock(addr_map_list_lock);
+       spin_unlock_irqrestore(addr_map_list_lock, flags);
        IPC_RTR_ERR(
                "%s: Virtual address mapping [%p] not found\n",
                __func__, (void *)addr);
@@ -219,10 +219,11 @@ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list,
  * Return: 0 on success, standard Linux error code otherwise.
  */
 int ipc_router_mhi_xprt_add_addr_map(struct list_head *addr_map_list,
-                               struct mutex *addr_map_list_lock,
+                               spinlock_t *addr_map_list_lock,
                                struct rr_packet *pkt, void *virt_addr)
 {
        struct ipc_router_mhi_addr_map *addr_mapping;
+       unsigned long flags;
 
        if (!addr_map_list || !addr_map_list_lock)
                return -EINVAL;
@@ -231,11 +232,11 @@ int ipc_router_mhi_xprt_add_addr_map(struct list_head *addr_map_list,
                return -ENOMEM;
        addr_mapping->virt_addr = virt_addr;
        addr_mapping->pkt = pkt;
-       mutex_lock(addr_map_list_lock);
+       spin_lock_irqsave(addr_map_list_lock, flags);
        if (addr_mapping->pkt)
                kref_get(&addr_mapping->pkt->ref);
        list_add_tail(&addr_mapping->list_node, addr_map_list);
-       mutex_unlock(addr_map_list_lock);
+       spin_unlock_irqrestore(addr_map_list_lock, flags);
        return 0;
 }
 
@@ -719,12 +720,11 @@ static void mhi_xprt_xfer_event(struct mhi_cb_info *cb_info)
        mhi_xprtp = (struct ipc_router_mhi_xprt *)(cb_info->result->user_data);
        if (cb_info->chan == mhi_xprtp->ch_hndl.out_chan_id) {
                out_addr = cb_info->result->buf_addr;
-               mutex_lock(&mhi_xprtp->ch_hndl.state_lock);
-               ipc_router_mhi_xprt_find_addr_map(&mhi_xprtp->tx_addr_map_list,
+               ipc_router_mhi_xprt_find_addr_map(
+                                       &mhi_xprtp->tx_addr_map_list,
                                        &mhi_xprtp->tx_addr_map_list_lock,
                                        out_addr);
                wake_up(&mhi_xprtp->write_wait_q);
-               mutex_unlock(&mhi_xprtp->ch_hndl.state_lock);
        } else if (cb_info->chan == mhi_xprtp->ch_hndl.in_chan_id) {
                queue_work(mhi_xprtp->wq, &mhi_xprtp->read_work);
        } else {
@@ -875,9 +875,9 @@ static int ipc_router_mhi_config_init(
        mhi_xprtp->ch_hndl.num_trbs = IPC_ROUTER_MHI_XPRT_NUM_TRBS;
        mhi_xprtp->ch_hndl.mhi_xprtp = mhi_xprtp;
        INIT_LIST_HEAD(&mhi_xprtp->tx_addr_map_list);
-       mutex_init(&mhi_xprtp->tx_addr_map_list_lock);
+       spin_lock_init(&mhi_xprtp->tx_addr_map_list_lock);
        INIT_LIST_HEAD(&mhi_xprtp->rx_addr_map_list);
-       mutex_init(&mhi_xprtp->rx_addr_map_list_lock);
+       spin_lock_init(&mhi_xprtp->rx_addr_map_list_lock);
 
        rc = ipc_router_mhi_driver_register(mhi_xprtp);
        return rc;
index 092b1c1..924c826 100644 (file)
@@ -95,7 +95,7 @@ int msm_dump_data_add_minidump(struct msm_dump_entry *entry)
 
        data = (struct msm_dump_data *)(phys_to_virt(entry->addr));
        if (!strcmp(data->name, "")) {
-               pr_info("Entry name is NULL, Use ID %d for minidump\n",
+               pr_debug("Entry name is NULL, Use ID %d for minidump\n",
                         entry->id);
                snprintf(md_entry.name, sizeof(md_entry.name), "KMDT0x%X",
                         entry->id);
@@ -133,7 +133,7 @@ int msm_dump_data_register(enum msm_dump_table_ids id,
        dmac_flush_range(table, (void *)table + sizeof(struct msm_dump_table));
 
        if (msm_dump_data_add_minidump(entry))
-               pr_info("Failed to add entry in Minidump table\n");
+               pr_err("Failed to add entry in Minidump table\n");
 
        return 0;
 }
index 1cb36bf..3002330 100644 (file)
@@ -62,24 +62,31 @@ struct md_table {
        struct md_region        entry[MAX_NUM_ENTRIES];
 };
 
+/*
+ * md_elfhdr: Minidump table elf header
+ * @md_ehdr: elf main header
+ * @shdr: Section header
+ * @phdr: Program header
+ * @elf_offset: section offset in elf
+ * @strtable_idx: string table current index position
+ */
+struct md_elfhdr {
+       struct elfhdr   *md_ehdr;
+       struct elf_shdr *shdr;
+       struct elf_phdr *phdr;
+       u64             elf_offset;
+       u64             strtable_idx;
+};
+
 /* Protect elfheader and smem table from deferred calls contention */
 static DEFINE_SPINLOCK(mdt_lock);
-static bool minidump_enabled;
-static struct md_table minidump_table;
+static struct md_table minidump_table;
+static struct md_elfhdr        minidump_elfheader;
+
+bool minidump_enabled;
 static unsigned int pendings;
 static unsigned int region_idx = 1; /* First entry is ELF header*/
 
-/* ELF Header */
-static struct elfhdr *md_ehdr;
-/* ELF Program header */
-static struct elf_phdr *phdr;
-/* ELF Section header */
-static struct elf_shdr *shdr;
-/* Section offset in elf image */
-static u64 elf_offset;
-/* String table index, first byte must be '\0' */
-static unsigned int stringtable_idx = 1;
-
 static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr)
 {
        return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff);
@@ -90,6 +97,16 @@ static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx)
        return &elf_sheader(hdr)[idx];
 }
 
+static inline struct elf_phdr *elf_pheader(struct elfhdr *hdr)
+{
+       return (struct elf_phdr *)((size_t)hdr + (size_t)hdr->e_phoff);
+}
+
+static inline struct elf_phdr *elf_program(struct elfhdr *hdr, int idx)
+{
+       return &elf_pheader(hdr)[idx];
+}
+
 static inline char *elf_str_table(struct elfhdr *hdr)
 {
        if (hdr->e_shstrndx == SHN_UNDEF)
@@ -101,23 +118,24 @@ static inline char *elf_lookup_string(struct elfhdr *hdr, int offset)
 {
        char *strtab = elf_str_table(hdr);
 
-       if ((strtab == NULL) | (stringtable_idx < offset))
+       if ((strtab == NULL) || (minidump_elfheader.strtable_idx < offset))
                return NULL;
        return strtab + offset;
 }
 
 static inline unsigned int set_section_name(const char *name)
 {
-       char *strtab = elf_str_table(md_ehdr);
+       char *strtab = elf_str_table(minidump_elfheader.md_ehdr);
+       int idx = minidump_elfheader.strtable_idx;
        int ret = 0;
 
-       if ((strtab == NULL) | (name == NULL))
+       if ((strtab == NULL) || (name == NULL))
                return 0;
 
-       ret = stringtable_idx;
-       stringtable_idx += strlcpy((strtab + stringtable_idx),
-                               name, MAX_NAME_LENGTH);
-       stringtable_idx += 1;
+       ret = idx;
+       idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH);
+       minidump_elfheader.strtable_idx = idx + 1;
+
        return ret;
 }
 
@@ -137,11 +155,9 @@ static inline bool md_check_name(const char *name)
 static int md_update_smem_table(const struct md_region *entry)
 {
        struct md_smem_region *mdr;
-
-       if (!minidump_enabled) {
-               pr_info("Table in smem is not setup\n");
-               return -ENODEV;
-       }
+       struct elfhdr *hdr = minidump_elfheader.md_ehdr;
+       struct elf_shdr *shdr = elf_section(hdr, hdr->e_shnum++);
+       struct elf_phdr *phdr = elf_program(hdr, hdr->e_phnum++);
 
        mdr = &minidump_table.region[region_idx++];
 
@@ -155,36 +171,21 @@ static int md_update_smem_table(const struct md_region *entry)
        shdr->sh_addr = (elf_addr_t)entry->virt_addr;
        shdr->sh_size = mdr->size;
        shdr->sh_flags = SHF_WRITE;
-       shdr->sh_offset = elf_offset;
+       shdr->sh_offset = minidump_elfheader.elf_offset;
        shdr->sh_entsize = 0;
 
        phdr->p_type = PT_LOAD;
-       phdr->p_offset = elf_offset;
+       phdr->p_offset = minidump_elfheader.elf_offset;
        phdr->p_vaddr = entry->virt_addr;
        phdr->p_paddr = entry->phys_addr;
        phdr->p_filesz = phdr->p_memsz =  mdr->size;
        phdr->p_flags = PF_R | PF_W;
 
-       md_ehdr->e_shnum += 1;
-       md_ehdr->e_phnum += 1;
-       elf_offset += shdr->sh_size;
-       shdr++;
-       phdr++;
+       minidump_elfheader.elf_offset += shdr->sh_size;
 
        return 0;
 }
 
-bool msm_minidump_enabled(void)
-{
-       bool ret;
-
-       spin_lock(&mdt_lock);
-       ret = minidump_enabled;
-       spin_unlock(&mdt_lock);
-       return ret;
-}
-EXPORT_SYMBOL(msm_minidump_enabled);
-
 int msm_minidump_add_region(const struct md_region *entry)
 {
        u32 entries;
@@ -196,19 +197,19 @@ int msm_minidump_add_region(const struct md_region *entry)
 
        if (((strlen(entry->name) > MAX_NAME_LENGTH) ||
                 md_check_name(entry->name)) && !entry->virt_addr) {
-               pr_info("Invalid entry details\n");
+               pr_err("Invalid entry details\n");
                return -EINVAL;
        }
 
        if (!IS_ALIGNED(entry->size, 4)) {
-               pr_info("size should be 4 byte aligned\n");
+               pr_err("size should be 4 byte aligned\n");
                return -EINVAL;
        }
 
        spin_lock(&mdt_lock);
        entries = minidump_table.num_regions;
        if (entries >= MAX_NUM_ENTRIES) {
-               pr_info("Maximum entries reached.\n");
+               pr_err("Maximum entries reached.\n");
                spin_unlock(&mdt_lock);
                return -ENOMEM;
        }
@@ -238,23 +239,32 @@ EXPORT_SYMBOL(msm_minidump_add_region);
 static int msm_minidump_add_header(void)
 {
        struct md_smem_region *mdreg = &minidump_table.region[0];
-       char *banner;
+       struct elfhdr *md_ehdr;
+       struct elf_shdr *shdr;
+       struct elf_phdr *phdr;
        unsigned int strtbl_off, elfh_size, phdr_off;
+       char *banner;
 
+       /* Header buffer contains:
+        * elf header, MAX_NUM_ENTRIES+1 of section and program elf headers,
+        * string table section and linux banner.
+        */
        elfh_size = sizeof(*md_ehdr) + MAX_STRTBL_SIZE + MAX_MEM_LENGTH +
                ((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 1));
 
-       md_ehdr = kzalloc(elfh_size, GFP_KERNEL);
-       if (!md_ehdr)
+       minidump_elfheader.md_ehdr = kzalloc(elfh_size, GFP_KERNEL);
+       if (!minidump_elfheader.md_ehdr)
                return -ENOMEM;
 
        strlcpy(mdreg->name, "KELF_HEADER", sizeof(mdreg->name));
-       mdreg->address = virt_to_phys(md_ehdr);
+       mdreg->address = virt_to_phys(minidump_elfheader.md_ehdr);
        mdreg->size = elfh_size;
 
-       /* Section headers*/
-       shdr = (struct elf_shdr *)(md_ehdr + 1);
-       phdr = (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES);
+       md_ehdr = minidump_elfheader.md_ehdr;
+       /* Assign section/program headers offset */
+       minidump_elfheader.shdr = shdr = (struct elf_shdr *)(md_ehdr + 1);
+       minidump_elfheader.phdr = phdr =
+                                (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES);
        phdr_off = sizeof(*md_ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES);
 
        memcpy(md_ehdr->e_ident, ELFMAG, SELFMAG);
@@ -268,18 +278,19 @@ static int msm_minidump_add_header(void)
        md_ehdr->e_ehsize = sizeof(*md_ehdr);
        md_ehdr->e_phoff = phdr_off;
        md_ehdr->e_phentsize = sizeof(*phdr);
-       md_ehdr->e_phnum = 1;
        md_ehdr->e_shoff = sizeof(*md_ehdr);
        md_ehdr->e_shentsize = sizeof(*shdr);
-       md_ehdr->e_shnum = 3;    /* NULL, STR TABLE, Linux banner */
        md_ehdr->e_shstrndx = 1;
 
-       elf_offset = elfh_size;
+       minidump_elfheader.elf_offset = elfh_size;
+
+       /*
+        * First section header should be NULL,
+        * 2nd section is string table.
+        */
+       minidump_elfheader.strtable_idx = 1;
        strtbl_off = sizeof(*md_ehdr) +
                        ((sizeof(*phdr) + sizeof(*shdr)) * MAX_NUM_ENTRIES);
-       /* First section header should be NULL
-        * 2nd entry for string table
-        */
        shdr++;
        shdr->sh_type = SHT_STRTAB;
        shdr->sh_offset = (elf_addr_t)strtbl_off;
@@ -289,7 +300,15 @@ static int msm_minidump_add_header(void)
        shdr->sh_name = set_section_name("STR_TBL");
        shdr++;
 
-       /* 3rd entry for linux banner */
+       /* 3rd section is for minidump_table VA, used by parsers */
+       shdr->sh_type = SHT_PROGBITS;
+       shdr->sh_entsize = 0;
+       shdr->sh_flags = 0;
+       shdr->sh_addr = (elf_addr_t)&minidump_table;
+       shdr->sh_name = set_section_name("minidump_table");
+       shdr++;
+
+       /* 4th section is linux banner */
        banner = (char *)md_ehdr + strtbl_off + MAX_STRTBL_SIZE;
        strlcpy(banner, linux_banner, MAX_MEM_LENGTH);
 
@@ -300,7 +319,6 @@ static int msm_minidump_add_header(void)
        shdr->sh_entsize = 0;
        shdr->sh_flags = SHF_WRITE;
        shdr->sh_name = set_section_name("linux_banner");
-       shdr++;
 
        phdr->p_type = PT_LOAD;
        phdr->p_offset = (elf_addr_t)(strtbl_off + MAX_STRTBL_SIZE);
@@ -309,8 +327,9 @@ static int msm_minidump_add_header(void)
        phdr->p_filesz = phdr->p_memsz = strlen(linux_banner) + 1;
        phdr->p_flags = PF_R | PF_W;
 
-       md_ehdr->e_phnum += 1;
-       phdr++;
+       /* Update headers count*/
+       md_ehdr->e_phnum = 1;
+       md_ehdr->e_shnum = 4;
 
        return 0;
 }
@@ -325,13 +344,13 @@ static int __init msm_minidump_init(void)
        smem_table = smem_get_entry(SMEM_MINIDUMP_TABLE_ID, &size, 0,
                                        SMEM_ANY_HOST_FLAG);
        if (IS_ERR_OR_NULL(smem_table)) {
-               pr_info("SMEM is not initialized.\n");
+               pr_err("SMEM is not initialized.\n");
                return -ENODEV;
        }
 
        if ((smem_table->next_avail_offset + MAX_MEM_LENGTH) >
                 smem_table->smem_length) {
-               pr_info("SMEM memory not available.\n");
+               pr_err("SMEM memory not available.\n");
                return -ENOMEM;
        }
 
@@ -353,10 +372,10 @@ static int __init msm_minidump_init(void)
        for (i = 0; i < pendings; i++) {
                mdr = &minidump_table.entry[i];
                if (md_update_smem_table(mdr)) {
-                       pr_info("Unable to add entry %s to smem table\n",
+                       pr_err("Unable to add entry %s to smem table\n",
                                mdr->name);
                        spin_unlock(&mdt_lock);
-                       return -ENODEV;
+                       return -ENOENT;
                }
        }
 
index c61a868..5199614 100644 (file)
@@ -118,12 +118,7 @@ static void kryo_write_pmresr(int reg, int l_h, u32 val)
 
 static u32 kryo_read_pmresr(int reg, int l_h)
 {
-       u32 val;
-
-       if (reg > KRYO_MAX_L1_REG) {
-               pr_err("Invalid read of RESR reg %d\n", reg);
-               return 0;
-       }
+       u32 val = 0;
 
        if (l_h == RESR_L) {
                switch (reg) {
@@ -136,6 +131,9 @@ static u32 kryo_read_pmresr(int reg, int l_h)
                case 2:
                        asm volatile("mrs %0, " pmresr2l_el0 : "=r" (val));
                        break;
+               default:
+                       WARN_ONCE(1, "Invalid read of RESR reg %d\n", reg);
+                       break;
                }
        } else {
                switch (reg) {
@@ -148,6 +146,9 @@ static u32 kryo_read_pmresr(int reg, int l_h)
                case 2:
                        asm volatile("mrs %0," pmresr2h_el0 : "=r" (val));
                        break;
+               default:
+                       WARN_ONCE(1, "Invalid read of RESR reg %d\n", reg);
+                       break;
                }
        }
 
index 6e5ddc4..3415338 100644 (file)
@@ -917,13 +917,13 @@ out:
                                                priv->region_start),
                                        VMID_HLOS);
                        }
+                       if (desc->clear_fw_region && priv->region_start)
+                               pil_clear_segment(desc);
                        dma_free_attrs(desc->dev, priv->region_size,
                                        priv->region, priv->region_start,
                                        &desc->attrs);
                        priv->region = NULL;
                }
-               if (desc->clear_fw_region && priv->region_start)
-                       pil_clear_segment(desc);
                pil_release_mmap(desc);
        }
        return ret;
index 4ba9243..6e7d34a 100644 (file)
@@ -377,6 +377,12 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 
        drvdata = file->private_data;
 
+       if (IS_ERR(priv_arg)) {
+               dev_err(drvdata->dev, "%s: invalid user space pointer %lu\n",
+                       __func__, arg);
+               return -EINVAL;
+       }
+
        mutex_lock(&drvdata->mutex);
 
        pr_debug("qbt1000_ioctl %d\n", cmd);
@@ -401,6 +407,13 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        goto end;
                }
 
+               if (strcmp(app.name, FP_APP_NAME)) {
+                       dev_err(drvdata->dev, "%s: Invalid app name\n",
+                               __func__);
+                       rc = -EINVAL;
+                       goto end;
+               }
+
                if (drvdata->app_handle) {
                        dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n",
                                __func__);
@@ -414,6 +427,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                }
 
                pr_debug("app %s load before\n", app.name);
+               app.name[MAX_NAME_SIZE - 1] = '\0';
 
                /* start the TZ app */
                rc = qseecom_start_app(
@@ -427,7 +441,8 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                                pr_err("App %s failed to set bw\n", app.name);
                        }
                } else {
-                       pr_err("app %s failed to load\n", app.name);
+                       dev_err(drvdata->dev, "%s: Fingerprint Trusted App failed to load\n",
+                               __func__);
                        goto end;
                }
 
@@ -447,9 +462,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 
                pr_debug("app %s load after\n", app.name);
 
-               if (!strcmp(app.name, FP_APP_NAME))
-                       drvdata->fp_app_handle = drvdata->app_handle;
-
+               drvdata->fp_app_handle = drvdata->app_handle;
                break;
        }
        case QBT1000_UNLOAD_APP:
index 128ea43..a275537 100644 (file)
@@ -514,19 +514,19 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
                        mutex_unlock(&svc->m_lock);
                        return NULL;
                }
-               if (!svc->port_cnt && !svc->svc_cnt)
+               if (!svc->svc_cnt)
                        clnt->svc_cnt++;
                svc->port_cnt++;
                svc->port_fn[temp_port] = svc_fn;
                svc->port_priv[temp_port] = priv;
+               svc->svc_cnt++;
        } else {
                if (!svc->fn) {
-                       if (!svc->port_cnt && !svc->svc_cnt)
+                       if (!svc->svc_cnt)
                                clnt->svc_cnt++;
                        svc->fn = svc_fn;
-                       if (svc->port_cnt)
-                               svc->svc_cnt++;
                        svc->priv = priv;
+                       svc->svc_cnt++;
                }
        }
 
@@ -745,29 +745,28 @@ int apr_deregister(void *handle)
        if (!handle)
                return -EINVAL;
 
+       if (!svc->svc_cnt) {
+               pr_err("%s: svc already deregistered. svc = %pK\n",
+                       __func__, svc);
+               return -EINVAL;
+       }
+
        mutex_lock(&svc->m_lock);
        dest_id = svc->dest_id;
        client_id = svc->client_id;
        clnt = &client[dest_id][client_id];
 
-       if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+       if (svc->svc_cnt > 0) {
                if (svc->port_cnt)
                        svc->port_cnt--;
-               else if (svc->svc_cnt)
-                       svc->svc_cnt--;
-               if (!svc->port_cnt && !svc->svc_cnt) {
+               svc->svc_cnt--;
+               if (!svc->svc_cnt) {
                        client[dest_id][client_id].svc_cnt--;
-                       svc->need_reset = 0x0;
-               }
-       } else if (client[dest_id][client_id].svc_cnt > 0) {
-               client[dest_id][client_id].svc_cnt--;
-               if (!client[dest_id][client_id].svc_cnt) {
-                       svc->need_reset = 0x0;
                        pr_debug("%s: service is reset %pK\n", __func__, svc);
                }
        }
 
-       if (!svc->port_cnt && !svc->svc_cnt) {
+       if (!svc->svc_cnt) {
                svc->priv = NULL;
                svc->id = 0;
                svc->fn = NULL;
index 369fb27..f3e96f9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010, 2014, 2016, 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
@@ -24,11 +24,20 @@ int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
                u32 flags;
                u32 addr;
        } cmd;
+       struct scm_desc desc = {0};
+
+       if (!is_scm_armv8()) {
+               cmd.addr = addr;
+               cmd.flags = flags;
+               return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR,
+                               &cmd, sizeof(cmd), NULL, 0);
+       }
+
+       desc.args[0] = addr;
+       desc.args[1] = flags;
+       desc.arginfo = SCM_ARGS(2);
 
-       cmd.addr = addr;
-       cmd.flags = flags;
-       return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR,
-                       &cmd, sizeof(cmd), NULL, 0);
+       return scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, SCM_BOOT_ADDR), &desc);
 }
 EXPORT_SYMBOL(scm_set_boot_addr);
 
index 68592fe..b5681a5 100644 (file)
@@ -376,13 +376,6 @@ static void root_service_service_arrive(struct work_struct *work)
        mutex_unlock(&qmi_client_release_lock);
        pr_info("Connection established between QMI handle and %d service\n",
                                                        data->instance_id);
-       /* Register for indication messages about service */
-       rc = qmi_register_ind_cb(data->clnt_handle, root_service_service_ind_cb,
-                                                       (void *)data);
-       if (rc < 0)
-               pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
-                                                       data->instance_id, rc);
-
        mutex_lock(&notif_add_lock);
        mutex_lock(&service_list_lock);
        list_for_each_entry(service_notif, &service_list, list) {
@@ -405,6 +398,12 @@ static void root_service_service_arrive(struct work_struct *work)
        }
        mutex_unlock(&service_list_lock);
        mutex_unlock(&notif_add_lock);
+       /* Register for indication messages about service */
+       rc = qmi_register_ind_cb(data->clnt_handle,
+               root_service_service_ind_cb, (void *)data);
+       if (rc < 0)
+               pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
+                                                       data->instance_id, rc);
 }
 
 static void root_service_service_exit(struct qmi_client_info *data,
index c1d8748..b9903fe 100644 (file)
@@ -65,6 +65,7 @@ enum {
        HW_PLATFORM_RCM = 21,
        HW_PLATFORM_STP = 23,
        HW_PLATFORM_SBC = 24,
+       HW_PLATFORM_ADP = 25,
        HW_PLATFORM_INVALID
 };
 
@@ -85,6 +86,7 @@ const char *hw_platform[] = {
        [HW_PLATFORM_DTV] = "DTV",
        [HW_PLATFORM_STP] = "STP",
        [HW_PLATFORM_SBC] = "SBC",
+       [HW_PLATFORM_ADP] = "ADP",
 };
 
 enum {
@@ -111,6 +113,22 @@ const char *qrd_hw_platform_subtype[] = {
 };
 
 enum {
+       PLATFORM_SUBTYPE_MOJAVE_V1 = 0x0,
+       PLATFORM_SUBTYPE_MMX = 0x1,
+       PLATFORM_SUBTYPE_MOJAVE_FULL_V2 = 0x2,
+       PLATFORM_SUBTYPE_MOJAVE_BARE_V2 = 0x3,
+       PLATFORM_SUBTYPE_ADP_INVALID,
+};
+
+const char *adp_hw_platform_subtype[] = {
+       [PLATFORM_SUBTYPE_MOJAVE_V1] = "MOJAVE_V1",
+       [PLATFORM_SUBTYPE_MMX] = "MMX",
+       [PLATFORM_SUBTYPE_MOJAVE_FULL_V2] = "_MOJAVE_V2_FULL",
+       [PLATFORM_SUBTYPE_MOJAVE_BARE_V2] = "_MOJAVE_V2_BARE",
+       [PLATFORM_SUBTYPE_ADP_INVALID] = "INVALID",
+};
+
+enum {
        PLATFORM_SUBTYPE_UNKNOWN = 0x0,
        PLATFORM_SUBTYPE_CHARM = 0x1,
        PLATFORM_SUBTYPE_STRANGE = 0x2,
@@ -514,11 +532,13 @@ static struct msm_soc_info cpu_of_id[] = {
 
        /* 8996 IDs */
        [246] = {MSM_CPU_8996, "MSM8996"},
-       [310] = {MSM_CPU_8996, "MSM8996"},
-       [311] = {MSM_CPU_8996, "APQ8096"},
        [291] = {MSM_CPU_8996, "APQ8096"},
        [305] = {MSM_CPU_8996, "MSM8996pro"},
+       [310] = {MSM_CPU_8996, "MSM8996"},
+       [311] = {MSM_CPU_8996, "APQ8096"},
        [312] = {MSM_CPU_8996, "APQ8096pro"},
+       [315] = {MSM_CPU_8996, "MSM8996pro"},
+       [316] = {MSM_CPU_8996, "APQ8096pro"},
 
        /* 8976 ID */
        [266] = {MSM_CPU_8976, "MSM8976"},
@@ -804,6 +824,14 @@ msm_get_platform_subtype(struct device *dev,
                }
                return snprintf(buf, PAGE_SIZE, "%-.32s\n",
                                        qrd_hw_platform_subtype[hw_subtype]);
+       }
+       if (socinfo_get_platform_type() == HW_PLATFORM_ADP) {
+               if (hw_subtype >= PLATFORM_SUBTYPE_ADP_INVALID) {
+                       pr_err("Invalid hardware platform sub type for adp found\n");
+                       hw_subtype = PLATFORM_SUBTYPE_ADP_INVALID;
+               }
+               return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+                                       adp_hw_platform_subtype[hw_subtype]);
        } else {
                if (hw_subtype >= PLATFORM_SUBTYPE_INVALID) {
                        pr_err("Invalid hardware platform subtype\n");
@@ -1225,10 +1253,6 @@ static void * __init setup_dummy_socinfo(void)
                dummy_socinfo.id = 246;
                strlcpy(dummy_socinfo.build_id, "msm8996 - ",
                        sizeof(dummy_socinfo.build_id));
-       } else if (early_machine_is_msm8996_auto()) {
-               dummy_socinfo.id = 310;
-               strlcpy(dummy_socinfo.build_id, "msm8996-auto - ",
-               sizeof(dummy_socinfo.build_id));
        } else if (early_machine_is_msm8929()) {
                dummy_socinfo.id = 268;
                strlcpy(dummy_socinfo.build_id, "msm8929 - ",
index d3d0b85..51f4ec7 100644 (file)
@@ -480,15 +480,19 @@ static void send_sysmon_notif(struct subsys_device *dev)
        mutex_unlock(&subsys_list_lock);
 }
 
-static void for_each_subsys_device(struct subsys_device **list, unsigned count,
-               void *data, void (*fn)(struct subsys_device *, void *))
+static int for_each_subsys_device(struct subsys_device **list, unsigned count,
+               void *data, int (*fn)(struct subsys_device *, void *))
 {
+       int ret;
        while (count--) {
                struct subsys_device *dev = *list++;
                if (!dev)
                        continue;
-               fn(dev, data);
+               ret = fn(dev, data);
+               if (ret)
+                       return ret;
        }
+       return 0;
 }
 
 static void notify_each_subsys_device(struct subsys_device **list,
@@ -590,21 +594,31 @@ static int wait_for_err_ready(struct subsys_device *subsys)
        return 0;
 }
 
-static void subsystem_shutdown(struct subsys_device *dev, void *data)
+static int subsystem_shutdown(struct subsys_device *dev, void *data)
 {
        const char *name = dev->desc->name;
+       int ret;
 
        pr_info("[%s:%d]: Shutting down %s\n",
                        current->comm, current->pid, name);
-       if (dev->desc->shutdown(dev->desc, true) < 0)
-               panic("subsys-restart: [%s:%d]: Failed to shutdown %s!",
-                       current->comm, current->pid, name);
+       ret = dev->desc->shutdown(dev->desc, true);
+       if (ret < 0) {
+               if (!dev->desc->ignore_ssr_failure) {
+                       panic("subsys-restart: [%s:%d]: Failed to shutdown %s!",
+                               current->comm, current->pid, name);
+               } else {
+                       pr_err("Shutdown failure on %s\n", name);
+                       return ret;
+               }
+       }
        dev->crash_count++;
        subsys_set_state(dev, SUBSYS_OFFLINE);
        disable_all_irqs(dev);
+
+       return 0;
 }
 
-static void subsystem_ramdump(struct subsys_device *dev, void *data)
+static int subsystem_ramdump(struct subsys_device *dev, void *data)
 {
        const char *name = dev->desc->name;
 
@@ -613,15 +627,17 @@ static void subsystem_ramdump(struct subsys_device *dev, void *data)
                        pr_warn("%s[%s:%d]: Ramdump failed.\n",
                                name, current->comm, current->pid);
        dev->do_ramdump_on_put = false;
+       return 0;
 }
 
-static void subsystem_free_memory(struct subsys_device *dev, void *data)
+static int subsystem_free_memory(struct subsys_device *dev, void *data)
 {
        if (dev->desc->free_memory)
                dev->desc->free_memory(dev->desc);
+       return 0;
 }
 
-static void subsystem_powerup(struct subsys_device *dev, void *data)
+static int subsystem_powerup(struct subsys_device *dev, void *data)
 {
        const char *name = dev->desc->name;
        int ret;
@@ -629,11 +645,17 @@ static void subsystem_powerup(struct subsys_device *dev, void *data)
        pr_info("[%s:%d]: Powering up %s\n", current->comm, current->pid, name);
        init_completion(&dev->err_ready);
 
-       if (dev->desc->powerup(dev->desc) < 0) {
+       ret = dev->desc->powerup(dev->desc);
+       if (ret < 0) {
                notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
                                                                NULL);
-               panic("[%s:%d]: Powerup error: %s!",
-                       current->comm, current->pid, name);
+               if (!dev->desc->ignore_ssr_failure) {
+                       panic("[%s:%d]: Powerup error: %s!",
+                               current->comm, current->pid, name);
+               } else {
+                       pr_err("Powerup failure on %s\n", name);
+                       return ret;
+               }
        }
        enable_all_irqs(dev);
 
@@ -641,11 +663,16 @@ static void subsystem_powerup(struct subsys_device *dev, void *data)
        if (ret) {
                notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
                                                                NULL);
-               panic("[%s:%d]: Timed out waiting for error ready: %s!",
-                       current->comm, current->pid, name);
+               if (!dev->desc->ignore_ssr_failure)
+                       panic("[%s:%d]: Timed out waiting for error ready: %s!",
+                               current->comm, current->pid, name);
+               else
+                       return ret;
        }
        subsys_set_state(dev, SUBSYS_ONLINE);
        subsys_set_crash_status(dev, CRASH_STATUS_NO_CRASH);
+
+       return 0;
 }
 
 static int __find_subsys(struct device *dev, void *data)
@@ -907,6 +934,7 @@ static void subsystem_restart_wq_func(struct work_struct *work)
        struct subsys_tracking *track;
        unsigned count;
        unsigned long flags;
+       int ret;
 
        /*
         * It's OK to not take the registration lock at this point.
@@ -954,7 +982,9 @@ static void subsystem_restart_wq_func(struct work_struct *work)
        pr_debug("[%s:%d]: Starting restart sequence for %s\n",
                        current->comm, current->pid, desc->name);
        notify_each_subsys_device(list, count, SUBSYS_BEFORE_SHUTDOWN, NULL);
-       for_each_subsys_device(list, count, NULL, subsystem_shutdown);
+       ret = for_each_subsys_device(list, count, NULL, subsystem_shutdown);
+       if (ret)
+               goto err;
        notify_each_subsys_device(list, count, SUBSYS_AFTER_SHUTDOWN, NULL);
 
        notify_each_subsys_device(list, count, SUBSYS_RAMDUMP_NOTIFICATION,
@@ -970,12 +1000,19 @@ static void subsystem_restart_wq_func(struct work_struct *work)
        for_each_subsys_device(list, count, NULL, subsystem_free_memory);
 
        notify_each_subsys_device(list, count, SUBSYS_BEFORE_POWERUP, NULL);
-       for_each_subsys_device(list, count, NULL, subsystem_powerup);
+       ret = for_each_subsys_device(list, count, NULL, subsystem_powerup);
+       if (ret)
+               goto err;
        notify_each_subsys_device(list, count, SUBSYS_AFTER_POWERUP, NULL);
 
        pr_info("[%s:%d]: Restart sequence for %s completed.\n",
                        current->comm, current->pid, desc->name);
 
+err:
+       /* Reset subsys count */
+       if (ret)
+               dev->count = 0;
+
        mutex_unlock(&soc_order_reg_lock);
        mutex_unlock(&track->lock);
 
@@ -1466,6 +1503,9 @@ static int subsys_parse_devicetree(struct subsys_desc *desc)
                        desc->generic_irq = ret;
        }
 
+       desc->ignore_ssr_failure = of_property_read_bool(pdev->dev.of_node,
+                                               "qcom,ignore-ssr-failure");
+
        order = ssr_parse_restart_orders(desc);
        if (IS_ERR(order)) {
                pr_err("Could not initialize SSR restart order, err = %ld\n",
index 58bf3d2..bfb7dd2 100644 (file)
@@ -3,7 +3,7 @@
  * drivers/staging/android/ion/ion.c
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -122,8 +122,6 @@ struct ion_handle {
        int id;
 };
 
-static struct ion_device *ion_dev;
-
 bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
 {
        return (buffer->flags & ION_FLAG_CACHED) &&
@@ -844,32 +842,45 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
 }
 EXPORT_SYMBOL(ion_unmap_kernel);
 
-static int ion_debug_client_show(struct seq_file *s, void *unused)
+static struct mutex debugfs_mutex;
+static struct rb_root *ion_root_client;
+static int is_client_alive(struct ion_client *client)
 {
-       struct ion_client *client = s->private;
-       struct rb_node *n, *cnode;
-       bool found = false;
-
-       down_write(&ion_dev->lock);
+       struct rb_node *node;
+       struct ion_client *tmp;
+       struct ion_device *dev;
 
-       if (!client || (client->dev != ion_dev)) {
-               up_write(&ion_dev->lock);
-               return -EINVAL;
-       }
+       node = ion_root_client->rb_node;
+       dev = container_of(ion_root_client, struct ion_device, clients);
 
-       cnode = rb_first(&ion_dev->clients);
-       for ( ; cnode; cnode = rb_next(cnode)) {
-               struct ion_client *c = rb_entry(cnode,
-                               struct ion_client, node);
-               if (client == c) {
-                       found = true;
-                       break;
+       down_read(&dev->lock);
+       while (node) {
+               tmp = rb_entry(node, struct ion_client, node);
+               if (client < tmp) {
+                       node = node->rb_left;
+               } else if (client > tmp) {
+                       node = node->rb_right;
+               } else {
+                       up_read(&dev->lock);
+                       return 1;
                }
        }
 
-       if (!found) {
-               up_write(&ion_dev->lock);
-               return -EINVAL;
+       up_read(&dev->lock);
+       return 0;
+}
+
+static int ion_debug_client_show(struct seq_file *s, void *unused)
+{
+       struct ion_client *client = s->private;
+       struct rb_node *n;
+
+       mutex_lock(&debugfs_mutex);
+       if (!is_client_alive(client)) {
+               seq_printf(s, "ion_client 0x%pK dead, can't dump its buffers\n",
+                          client);
+               mutex_unlock(&debugfs_mutex);
+               return 0;
        }
 
        seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n",
@@ -890,7 +901,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
                seq_printf(s, "\n");
        }
        mutex_unlock(&client->lock);
-       up_write(&ion_dev->lock);
+       mutex_unlock(&debugfs_mutex);
        return 0;
 }
 
@@ -1021,7 +1032,7 @@ void ion_client_destroy(struct ion_client *client)
        struct rb_node *n;
 
        pr_debug("%s: %d\n", __func__, __LINE__);
-       mutex_lock(&client->lock);
+       mutex_lock(&debugfs_mutex);
        while ((n = rb_first(&client->handles))) {
                struct ion_handle *handle = rb_entry(n, struct ion_handle,
                                                     node);
@@ -1029,7 +1040,6 @@ void ion_client_destroy(struct ion_client *client)
        }
 
        idr_destroy(&client->idr);
-       mutex_unlock(&client->lock);
 
        down_write(&dev->lock);
        if (client->task)
@@ -1042,6 +1052,7 @@ void ion_client_destroy(struct ion_client *client)
        kfree(client->display_name);
        kfree(client->name);
        kfree(client);
+       mutex_unlock(&debugfs_mutex);
 }
 EXPORT_SYMBOL(ion_client_destroy);
 
@@ -1838,7 +1849,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
        seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size");
        seq_puts(s, "----------------------------------------------------\n");
 
-       down_read(&dev->lock);
+       mutex_lock(&debugfs_mutex);
        for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
                struct ion_client *client = rb_entry(n, struct ion_client,
                                                     node);
@@ -1857,7 +1868,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
                                   client->pid, size);
                }
        }
-       up_read(&dev->lock);
+       mutex_unlock(&debugfs_mutex);
+
        seq_puts(s, "----------------------------------------------------\n");
        seq_puts(s, "orphaned allocations (info is from last known client):\n");
        mutex_lock(&dev->buffer_lock);
@@ -2095,7 +2107,8 @@ debugfs_done:
        init_rwsem(&idev->lock);
        plist_head_init(&idev->heaps);
        idev->clients = RB_ROOT;
-       ion_dev = idev;
+       ion_root_client = &idev->clients;
+       mutex_init(&debugfs_mutex);
        return idev;
 }
 EXPORT_SYMBOL(ion_device_create);
index 2cbea2a..6d1b0ac 100644 (file)
@@ -781,22 +781,6 @@ static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
                if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
                        SET_PSTATE_REPLY_OPTIONAL(param);
                /*
-                * The GlobalSAN iSCSI Initiator for MacOSX does
-                * not respond to MaxBurstLength, FirstBurstLength,
-                * DefaultTime2Wait or DefaultTime2Retain parameter keys.
-                * So, we set them to 'reply optional' here, and assume the
-                * the defaults from iscsi_parameters.h if the initiator
-                * is not RFC compliant and the keys are not negotiated.
-                */
-               if (!strcmp(param->name, MAXBURSTLENGTH))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
-               if (!strcmp(param->name, FIRSTBURSTLENGTH))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
-               if (!strcmp(param->name, DEFAULTTIME2WAIT))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
-               if (!strcmp(param->name, DEFAULTTIME2RETAIN))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
-               /*
                 * Required for gPXE iSCSI boot client
                 */
                if (!strcmp(param->name, MAXCONNECTIONS))
index 428b0d9..9359052 100644 (file)
@@ -731,21 +731,23 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
 {
        struct se_cmd *se_cmd = NULL;
        int rc;
+       bool op_scsi = false;
        /*
         * Determine if a struct se_cmd is associated with
         * this struct iscsi_cmd.
         */
        switch (cmd->iscsi_opcode) {
        case ISCSI_OP_SCSI_CMD:
-               se_cmd = &cmd->se_cmd;
-               __iscsit_free_cmd(cmd, true, shutdown);
+               op_scsi = true;
                /*
                 * Fallthrough
                 */
        case ISCSI_OP_SCSI_TMFUNC:
-               rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
-               if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
-                       __iscsit_free_cmd(cmd, true, shutdown);
+               se_cmd = &cmd->se_cmd;
+               __iscsit_free_cmd(cmd, op_scsi, shutdown);
+               rc = transport_generic_free_cmd(se_cmd, shutdown);
+               if (!rc && shutdown && se_cmd->se_sess) {
+                       __iscsit_free_cmd(cmd, op_scsi, shutdown);
                        target_put_sess_cmd(se_cmd);
                }
                break;
index 80f9de9..5cc80b8 100644 (file)
@@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        struct tty_struct *tty = tty_port_tty_get(&port->port);
        int i, ret;
 
-       read_mem32((u32 *) &size, addr, 4);
+       size = __le32_to_cpu(readl(addr));
        /*  DBG1( "%d bytes port: %d", size, index); */
 
        if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
index a0f9116..53e4d50 100644 (file)
@@ -810,6 +810,11 @@ static void atmel_complete_tx_dma(void *arg)
         */
        if (!uart_circ_empty(xmit))
                tasklet_schedule(&atmel_port->tasklet);
+       else if ((port->rs485.flags & SER_RS485_ENABLED) &&
+                !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+               /* DMA done, stop TX, start RX for RS485 */
+               atmel_start_rx(port);
+       }
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -912,12 +917,6 @@ static void atmel_tx_dma(struct uart_port *port)
                desc->callback = atmel_complete_tx_dma;
                desc->callback_param = atmel_port;
                atmel_port->cookie_tx = dmaengine_submit(desc);
-
-       } else {
-               if (port->rs485.flags & SER_RS485_ENABLED) {
-                       /* DMA done, stop TX, start RX for RS485 */
-                       atmel_start_rx(port);
-               }
        }
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1987,6 +1986,11 @@ static void atmel_flush_buffer(struct uart_port *port)
                atmel_uart_writel(port, ATMEL_PDC_TCR, 0);
                atmel_port->pdc_tx.ofs = 0;
        }
+       /*
+        * in uart_flush_buffer(), the xmit circular buffer has just
+        * been cleared, so we have to reset tx_len accordingly.
+        */
+       atmel_port->tx_len = 0;
 }
 
 /*
@@ -2499,6 +2503,9 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
        pdc_tx = atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN;
        atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
 
+       /* Make sure that tx path is actually able to send characters */
+       atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
+
        uart_console_write(port, s, count, atmel_console_putchar);
 
        /*
index db32923..efaac5e 100644 (file)
@@ -303,15 +303,17 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base)
        struct device *dev = msm_port->uart.dev;
        struct dma_slave_config conf;
        struct msm_dma *dma;
+       struct dma_chan *dma_chan;
        u32 crci = 0;
        int ret;
 
        dma = &msm_port->tx_dma;
 
        /* allocate DMA resources, if available */
-       dma->chan = dma_request_slave_channel_reason(dev, "tx");
-       if (IS_ERR(dma->chan))
+       dma_chan = dma_request_slave_channel_reason(dev, "tx");
+       if (IS_ERR(dma_chan))
                goto no_tx;
+       dma->chan = dma_chan;
 
        of_property_read_u32(dev->of_node, "qcom,tx-crci", &crci);
 
@@ -346,15 +348,17 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
        struct device *dev = msm_port->uart.dev;
        struct dma_slave_config conf;
        struct msm_dma *dma;
+       struct dma_chan *dma_chan;
        u32 crci = 0;
        int ret;
 
        dma = &msm_port->rx_dma;
 
        /* allocate DMA resources, if available */
-       dma->chan = dma_request_slave_channel_reason(dev, "rx");
-       if (IS_ERR(dma->chan))
+       dma_chan = dma_request_slave_channel_reason(dev, "rx");
+       if (IS_ERR(dma_chan))
                goto no_rx;
+       dma->chan = dma_chan;
 
        of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
 
@@ -1166,26 +1170,17 @@ static int msm_startup(struct uart_port *port)
        snprintf(msm_port->name, sizeof(msm_port->name),
                 "msm_serial%d", port->line);
 
-       ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
-                         msm_port->name, port);
-       if (unlikely(ret))
-               return ret;
-
        /*
         * UART clk must be kept enabled to
         * avoid losing received character
         */
        ret = clk_prepare_enable(msm_port->clk);
-       if (ret) {
-               goto err_clk;
+       if (ret)
                return ret;
-       }
 
        ret = clk_prepare_enable(msm_port->pclk);
-       if (ret) {
+       if (ret)
                goto err_pclk;
-               return ret;
-       }
 
        msm_serial_set_mnd_regs(port);
 
@@ -1213,12 +1208,21 @@ static int msm_startup(struct uart_port *port)
                msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
        }
 
+       ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
+                         msm_port->name, port);
+       if (unlikely(ret))
+               goto err_irq;
+
        return 0;
 
+err_irq:
+       if (msm_port->is_uartdm)
+               msm_release_dma(msm_port);
+
+       clk_disable_unprepare(msm_port->pclk);
+
 err_pclk:
        clk_disable_unprepare(msm_port->clk);
-err_clk:
-       free_irq(port->irq, port);
 
        return ret;
 }
index 755dbca..aa00bb5 100644 (file)
@@ -499,8 +499,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
         */
        tbuf_size =  max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
        tbuf = kzalloc(tbuf_size, GFP_KERNEL);
-       if (!tbuf)
-               return -ENOMEM;
+       if (!tbuf) {
+               status = -ENOMEM;
+               goto err_alloc;
+       }
 
        bufp = tbuf;
 
@@ -705,6 +707,7 @@ error:
        }
 
        kfree(tbuf);
+ err_alloc:
 
        /* any errors get returned through the urb completion */
        spin_lock_irq(&hcd_root_hub_lock);
index 41b1ef2..87912ea 100644 (file)
@@ -2613,8 +2613,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                if (ret < 0)
                        return ret;
 
-               /* The port state is unknown until the reset completes. */
-               if (!(portstatus & USB_PORT_STAT_RESET))
+               /*
+                * The port state is unknown until the reset completes.
+                *
+                * On top of that, some chips may require additional time
+                * to re-establish a connection after the reset is complete,
+                * so also wait for the connection to be re-established.
+                */
+               if (!(portstatus & USB_PORT_STAT_RESET) &&
+                   (portstatus & USB_PORT_STAT_CONNECTION))
                        break;
 
                /* switch to the long delay after two short delay failures */
index e394f12..ad9d6cc 100644 (file)
@@ -3597,7 +3597,8 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA)
                }
        }
 
-       power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_TYPE, &pval);
+       power_supply_get_property(mdwc->usb_psy,
+                       POWER_SUPPLY_PROP_REAL_TYPE, &pval);
        if (pval.intval != POWER_SUPPLY_TYPE_USB)
                return 0;
 
index 9608a79..658fcca 100644 (file)
@@ -261,6 +261,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status)
 {
        struct dwc3                     *dwc = dep->dwc;
+       unsigned int                    unmap_after_complete = false;
        int                             i;
 
        if (req->queued) {
@@ -285,11 +286,19 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
 
-       if (dwc->ep0_bounced && dep->number <= 1)
+       /*
+        * NOTICE we don't want to unmap before calling ->complete() if we're
+        * dealing with a bounced ep0 request. If we unmap it here, we would end
+        * up overwritting the contents of req->buf and this could confuse the
+        * gadget driver.
+        */
+       if (dwc->ep0_bounced && dep->number <= 1) {
                dwc->ep0_bounced = false;
-
-       usb_gadget_unmap_request(&dwc->gadget, &req->request,
-                       req->direction);
+               unmap_after_complete = true;
+       } else {
+               usb_gadget_unmap_request(&dwc->gadget,
+                               &req->request, req->direction);
+       }
 
        dev_dbg(dwc->dev, "request %pK from %s completed %d/%d ===> %d\n",
                        req, dep->name, req->request.actual,
@@ -300,6 +309,10 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        spin_unlock(&dwc->lock);
        usb_gadget_giveback_request(&dep->endpoint, &req->request);
        spin_lock(&dwc->lock);
+
+       if (unmap_after_complete)
+               usb_gadget_unmap_request(&dwc->gadget,
+                               &req->request, req->direction);
 }
 
 int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
index 5bcff5d..4ebd744 100644 (file)
@@ -167,6 +167,15 @@ static struct usb_endpoint_descriptor bulk_in_desc = {
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 };
 
+static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
+       .bLength =              sizeof(ss_bulk_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /* the following 2 values can be tweaked if necessary */
+       /* .bMaxBurst =         0, */
+       /* .bmAttributes =      0, */
+};
+
 /* B.6.2  Class-specific MS Bulk IN Endpoint Descriptor */
 static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {
        /* .bLength =           DYNAMIC */
@@ -720,6 +729,7 @@ fail:
 static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct usb_descriptor_header **midi_function;
+       struct usb_descriptor_header **midi_ss_function;
        struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
        struct usb_midi_in_jack_descriptor jack_in_emb_desc[MAX_PORTS];
        struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS];
@@ -727,7 +737,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_composite_dev *cdev = c->cdev;
        struct f_midi *midi = func_to_midi(f);
        struct usb_string *us;
-       int status, n, jack = 1, i = 0;
+       int status, n, jack = 1, i = 0, j = 0;
 
        midi->gadget = cdev->gadget;
        tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
@@ -767,11 +777,20 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        if (!midi->out_ep)
                goto fail;
 
+       /* allocate temporary function list for ss */
+       midi_ss_function = kcalloc((MAX_PORTS * 4) + 11,
+                               sizeof(*midi_ss_function), GFP_KERNEL);
+       if (!midi_ss_function) {
+               status = -ENOMEM;
+               goto fail;
+       }
+
        /* allocate temporary function list */
        midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
                                GFP_KERNEL);
        if (!midi_function) {
                status = -ENOMEM;
+               kfree(midi_ss_function);
                goto fail;
        }
 
@@ -785,6 +804,12 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc;
        midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc;
        midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc;
+       midi_ss_function[j++] =
+                       (struct usb_descriptor_header *) &ac_interface_desc;
+       midi_ss_function[j++] =
+                       (struct usb_descriptor_header *) &ac_header_desc;
+       midi_ss_function[j++] =
+                       (struct usb_descriptor_header *) &ms_interface_desc;
 
        /* calculate the header's wTotalLength */
        n = USB_DT_MS_HEADER_SIZE
@@ -793,6 +818,8 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        ms_header_desc.wTotalLength = cpu_to_le16(n);
 
        midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc;
+       midi_ss_function[j++] =
+                       (struct usb_descriptor_header *) &ms_header_desc;
 
        /* configure the external IN jacks, each linked to an embedded OUT jack */
        for (n = 0; n < midi->in_ports; n++) {
@@ -806,6 +833,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
                in_ext->bJackID                 = jack++;
                in_ext->iJack                   = 0;
                midi_function[i++] = (struct usb_descriptor_header *) in_ext;
+               midi_ss_function[j++] = (struct usb_descriptor_header *) in_ext;
 
                out_emb->bLength                = USB_DT_MIDI_OUT_SIZE(1);
                out_emb->bDescriptorType        = USB_DT_CS_INTERFACE;
@@ -817,6 +845,8 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
                out_emb->pins[0].baSourceID     = in_ext->bJackID;
                out_emb->iJack                  = 0;
                midi_function[i++] = (struct usb_descriptor_header *) out_emb;
+               midi_ss_function[j++] =
+                               (struct usb_descriptor_header *) out_emb;
 
                /* link it to the endpoint */
                ms_in_desc.baAssocJackID[n] = out_emb->bJackID;
@@ -834,6 +864,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
                in_emb->bJackID                 = jack++;
                in_emb->iJack                   = 0;
                midi_function[i++] = (struct usb_descriptor_header *) in_emb;
+               midi_ss_function[j++] = (struct usb_descriptor_header *) in_emb;
 
                out_ext->bLength =              USB_DT_MIDI_OUT_SIZE(1);
                out_ext->bDescriptorType =      USB_DT_CS_INTERFACE;
@@ -845,6 +876,8 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
                out_ext->pins[0].baSourceID =   in_emb->bJackID;
                out_ext->pins[0].baSourcePin =  1;
                midi_function[i++] = (struct usb_descriptor_header *) out_ext;
+               midi_ss_function[j++] =
+                               (struct usb_descriptor_header *) out_ext;
 
                /* link it to the endpoint */
                ms_out_desc.baAssocJackID[n] = in_emb->bJackID;
@@ -864,6 +897,16 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc;
        midi_function[i++] = NULL;
 
+       midi_ss_function[j++] = (struct usb_descriptor_header *) &bulk_out_desc;
+       midi_ss_function[j++] =
+                       (struct usb_descriptor_header *) &ss_bulk_comp_desc;
+       midi_ss_function[j++] = (struct usb_descriptor_header *) &ms_out_desc;
+       midi_ss_function[j++] = (struct usb_descriptor_header *) &bulk_in_desc;
+       midi_ss_function[j++] =
+                       (struct usb_descriptor_header *) &ss_bulk_comp_desc;
+       midi_ss_function[j++] = (struct usb_descriptor_header *) &ms_in_desc;
+       midi_ss_function[j++] = NULL;
+
        /*
         * support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
@@ -882,13 +925,23 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
                        goto fail_f_midi;
        }
 
+       if (gadget_is_superspeed(c->cdev->gadget)) {
+               bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024);
+               bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024);
+               f->ss_descriptors = usb_copy_descriptors(midi_ss_function);
+               if (!f->ss_descriptors)
+                       goto fail_f_midi;
+       }
+
        kfree(midi_function);
+       kfree(midi_ss_function);
 
        return 0;
 
 fail_f_midi:
        kfree(midi_function);
        usb_free_descriptors(f->hs_descriptors);
+       kfree(midi_ss_function);
 fail:
        f_midi_unregister_card(midi);
 fail_register:
index 43e0546..9123f16 100644 (file)
@@ -66,7 +66,7 @@ struct eth_dev {
 
        spinlock_t              req_lock;       /* guard {rx,tx}_reqs */
        struct list_head        tx_reqs, rx_reqs;
-       unsigned                tx_qlen;
+       atomic_t                tx_qlen;
 /* Minimum number of TX USB request queued to UDC */
 #define TX_REQ_THRESHOLD       5
        int                     no_tx_req_used;
@@ -568,6 +568,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
                dev_kfree_skb_any(skb);
        }
 
+       atomic_dec(&dev->tx_qlen);
        if (netif_carrier_ok(dev->net))
                netif_wake_queue(dev->net);
 }
@@ -741,20 +742,13 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
 
        req->length = length;
 
-       /* throttle highspeed IRQ rate back slightly */
-       if (gadget_is_dualspeed(dev->gadget) &&
-                        (dev->gadget->speed == USB_SPEED_HIGH) &&
-                        !list_empty(&dev->tx_reqs)) {
-               dev->tx_qlen++;
-               if (dev->tx_qlen == (dev->qmult/2)) {
-                       req->no_interrupt = 0;
-                       dev->tx_qlen = 0;
-               } else {
-                       req->no_interrupt = 1;
-               }
-       } else {
-               req->no_interrupt = 0;
-       }
+       /* throttle high/super speed IRQ rate back slightly */
+       if (gadget_is_dualspeed(dev->gadget))
+               req->no_interrupt = (((dev->gadget->speed == USB_SPEED_HIGH ||
+                                      dev->gadget->speed == USB_SPEED_SUPER)) &&
+                                       !list_empty(&dev->tx_reqs))
+                       ? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0)
+                       : 0;
 
        retval = usb_ep_queue(in, req, GFP_ATOMIC);
        switch (retval) {
@@ -763,6 +757,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
                break;
        case 0:
                net->trans_start = jiffies;
+               atomic_inc(&dev->tx_qlen);
        }
 
        if (retval) {
@@ -791,7 +786,7 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
        rx_fill(dev, gfp_flags);
 
        /* and open the tx floodgates */
-       dev->tx_qlen = 0;
+       atomic_set(&dev->tx_qlen, 0);
        netif_wake_queue(dev->net);
 }
 
index f7a7fc2..e8f9172 100644 (file)
@@ -268,3 +268,13 @@ config USB_CHAOSKEY
 
          To compile this driver as a module, choose M here: the
          module will be called chaoskey.
+
+config USB_QTI_KS_BRIDGE
+       tristate "USB QTI kick start bridge"
+       depends on USB
+       help
+         Say Y here if you have a QTI modem device connected via USB that
+         will be bridged in kernel space. This driver works as a bridge to pass
+         boot images, ram-dumps and efs sync.
+         To compile this driver as a module, choose M here: the module
+         will be called ks_bridge. If unsure, choose N.
index 45fd4ac..616902b 100644 (file)
@@ -29,3 +29,5 @@ obj-$(CONFIG_USB_CHAOSKEY)            += chaoskey.o
 
 obj-$(CONFIG_USB_SISUSBVGA)            += sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)      += lvstest.o
+
+obj-$(CONFIG_USB_QTI_KS_BRIDGE)                += ks_bridge.o
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
new file mode 100644 (file)
index 0000000..35f652c
--- /dev/null
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2012-2014, 2017, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+
+#define DRIVER_DESC    "USB host ks bridge driver"
+
+enum bus_id {
+       BUS_HSIC,
+       BUS_USB,
+       BUS_UNDEF,
+};
+
+#define BUSNAME_LEN    20
+
+static enum bus_id str_to_busid(const char *name)
+{
+       if (!strncasecmp("msm_hsic_host", name, BUSNAME_LEN))
+               return BUS_HSIC;
+       if (!strncasecmp("msm_ehci_host.0", name, BUSNAME_LEN))
+               return BUS_USB;
+       if (!strncasecmp("xhci-hcd.0.auto", name, BUSNAME_LEN))
+               return BUS_USB;
+
+       return BUS_UNDEF;
+}
+
+struct data_pkt {
+       int                     n_read;
+       char                    *buf;
+       size_t                  len;
+       struct list_head        list;
+       void                    *ctxt;
+};
+
+#define FILE_OPENED            BIT(0)
+#define USB_DEV_CONNECTED      BIT(1)
+#define NO_RX_REQS             10
+#define NO_BRIDGE_INSTANCES    4
+#define EFS_HSIC_BRIDGE_INDEX  2
+#define EFS_USB_BRIDGE_INDEX   3
+#define MAX_DATA_PKT_SIZE      16384
+#define PENDING_URB_TIMEOUT    10
+
+struct ksb_dev_info {
+       const char *name;
+};
+
+struct ks_bridge {
+       char                    *name;
+       spinlock_t              lock;
+       struct workqueue_struct *wq;
+       struct work_struct      to_mdm_work;
+       struct work_struct      start_rx_work;
+       struct list_head        to_mdm_list;
+       struct list_head        to_ks_list;
+       wait_queue_head_t       ks_wait_q;
+       wait_queue_head_t       pending_urb_wait;
+       atomic_t                tx_pending_cnt;
+       atomic_t                rx_pending_cnt;
+
+       struct ksb_dev_info     id_info;
+
+       /* cdev interface */
+       dev_t                   cdev_start_no;
+       struct cdev             cdev;
+       struct class            *class;
+       struct device           *device;
+
+       /* usb specific */
+       struct usb_device       *udev;
+       struct usb_interface    *ifc;
+       __u8                    in_epAddr;
+       __u8                    out_epAddr;
+       unsigned int            in_pipe;
+       unsigned int            out_pipe;
+       struct usb_anchor       submitted;
+
+       unsigned long           flags;
+
+       /* to handle INT IN ep */
+       unsigned int            period;
+
+#define DBG_MSG_LEN   40
+#define DBG_MAX_MSG   500
+       unsigned int    dbg_idx;
+       rwlock_t        dbg_lock;
+
+       char     (dbgbuf[DBG_MAX_MSG])[DBG_MSG_LEN];   /* buffer */
+};
+
+struct ks_bridge *__ksb[NO_BRIDGE_INSTANCES];
+
+/* by default debugging is enabled */
+static unsigned int enable_dbg = 1;
+module_param(enable_dbg, uint, S_IRUGO | S_IWUSR);
+
+static void
+dbg_log_event(struct ks_bridge *ksb, char *event, int d1, int d2)
+{
+       unsigned long flags;
+       unsigned long long t;
+       unsigned long nanosec;
+
+       if (!enable_dbg)
+               return;
+
+       write_lock_irqsave(&ksb->dbg_lock, flags);
+       t = cpu_clock(smp_processor_id());
+       nanosec = do_div(t, 1000000000)/1000;
+       scnprintf(ksb->dbgbuf[ksb->dbg_idx], DBG_MSG_LEN, "%5lu.%06lu:%s:%x:%x",
+                       (unsigned long)t, nanosec, event, d1, d2);
+
+       ksb->dbg_idx++;
+       ksb->dbg_idx = ksb->dbg_idx % DBG_MAX_MSG;
+       write_unlock_irqrestore(&ksb->dbg_lock, flags);
+}
+
+static
+struct data_pkt *ksb_alloc_data_pkt(size_t count, gfp_t flags, void *ctxt)
+{
+       struct data_pkt *pkt;
+
+       pkt = kzalloc(sizeof(struct data_pkt), flags);
+       if (!pkt)
+               return ERR_PTR(-ENOMEM);
+
+       pkt->buf = kmalloc(count, flags);
+       if (!pkt->buf) {
+               kfree(pkt);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       pkt->len = count;
+       INIT_LIST_HEAD(&pkt->list);
+       pkt->ctxt = ctxt;
+
+       return pkt;
+}
+
+static void ksb_free_data_pkt(struct data_pkt *pkt)
+{
+       kfree(pkt->buf);
+       kfree(pkt);
+}
+
+
+static void
+submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt);
+static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
+                               size_t count, loff_t *pos)
+{
+       int ret;
+       unsigned long flags;
+       struct ks_bridge *ksb = fp->private_data;
+       struct data_pkt *pkt = NULL;
+       size_t space, copied;
+
+read_start:
+       if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               return -ENODEV;
+
+       spin_lock_irqsave(&ksb->lock, flags);
+       if (list_empty(&ksb->to_ks_list)) {
+               spin_unlock_irqrestore(&ksb->lock, flags);
+               ret = wait_event_interruptible(ksb->ks_wait_q,
+                               !list_empty(&ksb->to_ks_list) ||
+                               !test_bit(USB_DEV_CONNECTED, &ksb->flags));
+               if (ret < 0)
+                       return ret;
+
+               goto read_start;
+       }
+
+       space = count;
+       copied = 0;
+       while (!list_empty(&ksb->to_ks_list) && space &&
+                       test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
+               size_t len;
+
+               pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
+               list_del_init(&pkt->list);
+               len = min_t(size_t, space, pkt->len - pkt->n_read);
+               spin_unlock_irqrestore(&ksb->lock, flags);
+
+               ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
+               if (ret) {
+                       dev_err(ksb->device,
+                                       "copy_to_user failed err:%d\n", ret);
+                       ksb_free_data_pkt(pkt);
+                       return -EFAULT;
+               }
+
+               pkt->n_read += len;
+               space -= len;
+               copied += len;
+
+               if (pkt->n_read == pkt->len) {
+                       /*
+                        * re-init the packet and queue it
+                        * for more data.
+                        */
+                       pkt->n_read = 0;
+                       pkt->len = MAX_DATA_PKT_SIZE;
+                       submit_one_urb(ksb, GFP_KERNEL, pkt);
+                       pkt = NULL;
+               }
+               spin_lock_irqsave(&ksb->lock, flags);
+       }
+
+       /* put the partial packet back in the list */
+       if (!space && pkt && pkt->n_read != pkt->len) {
+               if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
+                       list_add(&pkt->list, &ksb->to_ks_list);
+               else
+                       ksb_free_data_pkt(pkt);
+       }
+       spin_unlock_irqrestore(&ksb->lock, flags);
+
+       dbg_log_event(ksb, "KS_READ", copied, 0);
+
+       dev_dbg(ksb->device, "count:%zu space:%zu copied:%zu", count,
+                       space, copied);
+
+       return copied;
+}
+
+static void ksb_tx_cb(struct urb *urb)
+{
+       struct data_pkt *pkt = urb->context;
+       struct ks_bridge *ksb = pkt->ctxt;
+
+       dbg_log_event(ksb, "C TX_URB", urb->status, 0);
+       dev_dbg(&ksb->udev->dev, "status:%d", urb->status);
+
+       if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               usb_autopm_put_interface_async(ksb->ifc);
+
+       if (urb->status < 0)
+               pr_err_ratelimited("%s: urb failed with err:%d",
+                               ksb->id_info.name, urb->status);
+
+       ksb_free_data_pkt(pkt);
+
+       atomic_dec(&ksb->tx_pending_cnt);
+       wake_up(&ksb->pending_urb_wait);
+}
+
+static void ksb_tomdm_work(struct work_struct *w)
+{
+       struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
+       struct data_pkt *pkt;
+       unsigned long flags;
+       struct urb *urb;
+       int ret;
+
+       spin_lock_irqsave(&ksb->lock, flags);
+       while (!list_empty(&ksb->to_mdm_list)
+                       && test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
+               pkt = list_first_entry(&ksb->to_mdm_list,
+                               struct data_pkt, list);
+               list_del_init(&pkt->list);
+               spin_unlock_irqrestore(&ksb->lock, flags);
+
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       dbg_log_event(ksb, "TX_URB_MEM_FAIL", -ENOMEM, 0);
+                       pr_err_ratelimited("%s: unable to allocate urb",
+                                       ksb->id_info.name);
+                       ksb_free_data_pkt(pkt);
+                       return;
+               }
+
+               ret = usb_autopm_get_interface(ksb->ifc);
+               if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
+                       dbg_log_event(ksb, "TX_URB_AUTOPM_FAIL", ret, 0);
+                       pr_err_ratelimited("%s: autopm_get failed:%d",
+                                       ksb->id_info.name, ret);
+                       usb_free_urb(urb);
+                       ksb_free_data_pkt(pkt);
+                       return;
+               }
+               usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
+                               pkt->buf, pkt->len, ksb_tx_cb, pkt);
+               usb_anchor_urb(urb, &ksb->submitted);
+
+               dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
+
+               atomic_inc(&ksb->tx_pending_cnt);
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       dev_err(&ksb->udev->dev, "out urb submission failed");
+                       usb_unanchor_urb(urb);
+                       usb_free_urb(urb);
+                       ksb_free_data_pkt(pkt);
+                       usb_autopm_put_interface(ksb->ifc);
+                       atomic_dec(&ksb->tx_pending_cnt);
+                       wake_up(&ksb->pending_urb_wait);
+                       return;
+               }
+
+               usb_free_urb(urb);
+
+               spin_lock_irqsave(&ksb->lock, flags);
+       }
+       spin_unlock_irqrestore(&ksb->lock, flags);
+}
+
+static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
+                                size_t count, loff_t *pos)
+{
+       int                     ret;
+       struct data_pkt         *pkt;
+       unsigned long           flags;
+       struct ks_bridge        *ksb = fp->private_data;
+
+       if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               return -ENODEV;
+
+       if (count > MAX_DATA_PKT_SIZE)
+               count = MAX_DATA_PKT_SIZE;
+
+       pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
+       if (IS_ERR(pkt)) {
+               dev_err(ksb->device,
+                               "unable to allocate data packet");
+               return PTR_ERR(pkt);
+       }
+
+       ret = copy_from_user(pkt->buf, buf, count);
+       if (ret) {
+               dev_err(ksb->device,
+                               "copy_from_user failed: err:%d", ret);
+               ksb_free_data_pkt(pkt);
+               return ret;
+       }
+
+       spin_lock_irqsave(&ksb->lock, flags);
+       list_add_tail(&pkt->list, &ksb->to_mdm_list);
+       spin_unlock_irqrestore(&ksb->lock, flags);
+
+       queue_work(ksb->wq, &ksb->to_mdm_work);
+
+       dbg_log_event(ksb, "KS_WRITE", count, 0);
+
+       return count;
+}
+
+static int ksb_fs_open(struct inode *ip, struct file *fp)
+{
+       struct ks_bridge *ksb =
+                       container_of(ip->i_cdev, struct ks_bridge, cdev);
+
+       if (IS_ERR(ksb)) {
+               pr_err("ksb device not found");
+               return -ENODEV;
+       }
+
+       dev_dbg(ksb->device, ":%s", ksb->id_info.name);
+       dbg_log_event(ksb, "FS-OPEN", 0, 0);
+
+       fp->private_data = ksb;
+       set_bit(FILE_OPENED, &ksb->flags);
+
+       if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               queue_work(ksb->wq, &ksb->start_rx_work);
+
+       return 0;
+}
+
+static unsigned int ksb_fs_poll(struct file *file, poll_table *wait)
+{
+       struct ks_bridge        *ksb = file->private_data;
+       unsigned long           flags;
+       int                     ret = 0;
+
+       if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               return POLLERR;
+
+       poll_wait(file, &ksb->ks_wait_q, wait);
+       if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               return POLLERR;
+
+       spin_lock_irqsave(&ksb->lock, flags);
+       if (!list_empty(&ksb->to_ks_list))
+               ret = POLLIN | POLLRDNORM;
+       spin_unlock_irqrestore(&ksb->lock, flags);
+
+       return ret;
+}
+
+static int ksb_fs_release(struct inode *ip, struct file *fp)
+{
+       struct ks_bridge        *ksb = fp->private_data;
+
+       if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
+               dev_dbg(ksb->device, ":%s", ksb->id_info.name);
+       dbg_log_event(ksb, "FS-RELEASE", 0, 0);
+
+       clear_bit(FILE_OPENED, &ksb->flags);
+       fp->private_data = NULL;
+
+       return 0;
+}
+
+static const struct file_operations ksb_fops = {
+       .owner = THIS_MODULE,
+       .read = ksb_fs_read,
+       .write = ksb_fs_write,
+       .open = ksb_fs_open,
+       .release = ksb_fs_release,
+       .poll = ksb_fs_poll,
+};
+
+static struct ksb_dev_info ksb_fboot_dev[] = {
+       {
+               .name = "ks_hsic_bridge",
+       },
+       {
+               .name = "ks_usb_bridge",
+       },
+};
+
+static struct ksb_dev_info ksb_efs_hsic_dev = {
+       .name = "efs_hsic_bridge",
+};
+
+static struct ksb_dev_info ksb_efs_usb_dev = {
+       .name = "efs_usb_bridge",
+};
+static const struct usb_device_id ksb_usb_ids[] = {
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9008, 0),
+       .driver_info = (unsigned long)&ksb_fboot_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9025, 0), },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9091, 0), },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901D, 0), },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x900E, 0), },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x904C, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9075, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9079, 2),
+       .driver_info = (unsigned long)&ksb_efs_usb_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x908A, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x908E, 3),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909C, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909D, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909E, 3),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909F, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90A0, 2),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+       { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90A4, 3),
+       .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+
+       {} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
+
+static void ksb_rx_cb(struct urb *urb);
+static void
+submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt)
+{
+       struct urb *urb;
+       int ret;
+
+       urb = usb_alloc_urb(0, flags);
+       if (!urb) {
+               dev_err(&ksb->udev->dev, "unable to allocate urb");
+               ksb_free_data_pkt(pkt);
+               return;
+       }
+
+       if (ksb->period)
+               usb_fill_int_urb(urb, ksb->udev, ksb->in_pipe,
+                                pkt->buf, pkt->len,
+                                ksb_rx_cb, pkt, ksb->period);
+       else
+               usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
+                               pkt->buf, pkt->len,
+                               ksb_rx_cb, pkt);
+
+       usb_anchor_urb(urb, &ksb->submitted);
+
+       if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
+               usb_unanchor_urb(urb);
+               usb_free_urb(urb);
+               ksb_free_data_pkt(pkt);
+               return;
+       }
+
+       atomic_inc(&ksb->rx_pending_cnt);
+       ret = usb_submit_urb(urb, flags);
+       if (ret) {
+               dev_err(&ksb->udev->dev, "in urb submission failed");
+               usb_unanchor_urb(urb);
+               usb_free_urb(urb);
+               ksb_free_data_pkt(pkt);
+               atomic_dec(&ksb->rx_pending_cnt);
+               wake_up(&ksb->pending_urb_wait);
+               return;
+       }
+
+       dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+
+       usb_free_urb(urb);
+}
+static void ksb_rx_cb(struct urb *urb)
+{
+       struct data_pkt *pkt = urb->context;
+       struct ks_bridge *ksb = pkt->ctxt;
+       bool wakeup = true;
+
+       dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
+
+       dev_dbg(&ksb->udev->dev, "status:%d actual:%d", urb->status,
+                       urb->actual_length);
+
+       /*non zero len of data received while unlinking urb*/
+       if (urb->status == -ENOENT && (urb->actual_length > 0)) {
+               /*
+                * If we wakeup the reader process now, it may
+                * queue the URB before its reject flag gets
+                * cleared.
+                */
+               wakeup = false;
+               goto add_to_list;
+       }
+
+       if (urb->status < 0) {
+               if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
+                               && urb->status != -EPROTO)
+                       pr_err_ratelimited("%s: urb failed with err:%d",
+                                       ksb->id_info.name, urb->status);
+
+               if (!urb->actual_length) {
+                       ksb_free_data_pkt(pkt);
+                       goto done;
+               }
+       }
+
+       usb_mark_last_busy(ksb->udev);
+
+       if (urb->actual_length == 0) {
+               submit_one_urb(ksb, GFP_ATOMIC, pkt);
+               goto done;
+       }
+
+add_to_list:
+       spin_lock(&ksb->lock);
+       pkt->len = urb->actual_length;
+       list_add_tail(&pkt->list, &ksb->to_ks_list);
+       spin_unlock(&ksb->lock);
+       /* wake up read thread */
+       if (wakeup)
+               wake_up(&ksb->ks_wait_q);
+done:
+       atomic_dec(&ksb->rx_pending_cnt);
+       wake_up(&ksb->pending_urb_wait);
+}
+
+static void ksb_start_rx_work(struct work_struct *w)
+{
+       struct ks_bridge *ksb =
+                       container_of(w, struct ks_bridge, start_rx_work);
+       struct data_pkt *pkt;
+       struct urb *urb;
+       int i = 0;
+       int ret;
+       bool put = true;
+
+       ret = usb_autopm_get_interface(ksb->ifc);
+       if (ret < 0) {
+               if (ret != -EAGAIN && ret != -EACCES) {
+                       pr_err_ratelimited("%s: autopm_get failed:%d",
+                                       ksb->id_info.name, ret);
+                       return;
+               }
+               put = false;
+       }
+       for (i = 0; i < NO_RX_REQS; i++) {
+
+               if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+                       break;
+
+               pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
+               if (IS_ERR(pkt)) {
+                       dev_err(&ksb->udev->dev, "unable to allocate data pkt");
+                       break;
+               }
+
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       dev_err(&ksb->udev->dev, "unable to allocate urb");
+                       ksb_free_data_pkt(pkt);
+                       break;
+               }
+
+               if (ksb->period)
+                       usb_fill_int_urb(urb, ksb->udev, ksb->in_pipe,
+                                       pkt->buf, pkt->len,
+                                       ksb_rx_cb, pkt, ksb->period);
+               else
+                       usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
+                                       pkt->buf, pkt->len,
+                                       ksb_rx_cb, pkt);
+
+               usb_anchor_urb(urb, &ksb->submitted);
+
+               dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+
+               atomic_inc(&ksb->rx_pending_cnt);
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       dev_err(&ksb->udev->dev, "in urb submission failed");
+                       usb_unanchor_urb(urb);
+                       usb_free_urb(urb);
+                       ksb_free_data_pkt(pkt);
+                       atomic_dec(&ksb->rx_pending_cnt);
+                       wake_up(&ksb->pending_urb_wait);
+                       break;
+               }
+
+               usb_free_urb(urb);
+       }
+       if (put)
+               usb_autopm_put_interface_async(ksb->ifc);
+}
+
+static int
+ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
+{
+       __u8                            ifc_num, ifc_count, ksb_port_num;
+       struct usb_host_interface       *ifc_desc;
+       struct usb_endpoint_descriptor  *ep_desc;
+       int                             i;
+       struct ks_bridge                *ksb;
+       unsigned long                   flags;
+       struct data_pkt                 *pkt;
+       struct ksb_dev_info             *mdev, *fbdev;
+       struct usb_device               *udev;
+       unsigned int                    bus_id;
+       int                             ret;
+       bool                            free_mdev = false;
+
+       ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
+
+       udev = interface_to_usbdev(ifc);
+       ifc_count = udev->actconfig->desc.bNumInterfaces;
+       fbdev = mdev = (struct ksb_dev_info *)id->driver_info;
+
+       bus_id = str_to_busid(udev->bus->bus_name);
+       if (bus_id == BUS_UNDEF) {
+               dev_err(&udev->dev, "unknown usb bus %s, probe failed\n",
+                               udev->bus->bus_name);
+               return -ENODEV;
+       }
+
+       switch (id->idProduct) {
+       case 0x900E:
+       case 0x9025:
+       case 0x9091:
+       case 0x901D:
+               /* 1-1 mapping between ksb and udev port which starts with 1 */
+               ksb_port_num = udev->portnum - 1;
+               dev_dbg(&udev->dev, "ifc_count: %u, port_num:%u\n", ifc_count,
+                               ksb_port_num);
+               if (ifc_count > 1)
+                       return -ENODEV;
+               if (ksb_port_num >= NO_BRIDGE_INSTANCES) {
+                       dev_err(&udev->dev, "port-num:%u invalid. Try first\n",
+                                       ksb_port_num);
+                       ksb_port_num = 0;
+               }
+               ksb = __ksb[ksb_port_num];
+               if (ksb->ifc) {
+                       dev_err(&udev->dev, "port already in use\n");
+                       return -ENODEV;
+               }
+               mdev = kzalloc(sizeof(struct ksb_dev_info), GFP_KERNEL);
+               if (!mdev)
+                       return -ENOMEM;
+               free_mdev = true;
+               mdev->name = ksb->name;
+               break;
+       case 0x9008:
+               ksb = __ksb[bus_id];
+               mdev = &fbdev[bus_id];
+               break;
+       case 0x9048:
+       case 0x904C:
+       case 0x9075:
+       case 0x908A:
+       case 0x908E:
+       case 0x90A0:
+       case 0x909C:
+       case 0x909D:
+       case 0x909E:
+       case 0x909F:
+       case 0x90A4:
+               ksb = __ksb[EFS_HSIC_BRIDGE_INDEX];
+               break;
+       case 0x9079:
+               if (ifc_num != 2)
+                       return -ENODEV;
+               ksb = __ksb[EFS_USB_BRIDGE_INDEX];
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       if (!ksb) {
+               pr_err("ksb is not initialized");
+               return -ENODEV;
+       }
+
+       ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
+       ksb->ifc = ifc;
+       ifc_desc = ifc->cur_altsetting;
+       ksb->id_info = *mdev;
+
+       for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
+               ep_desc = &ifc_desc->endpoint[i].desc;
+
+               if (!ksb->in_epAddr && (usb_endpoint_is_bulk_in(ep_desc))) {
+                       ksb->in_epAddr = ep_desc->bEndpointAddress;
+                       ksb->period = 0;
+               }
+
+               if (!ksb->in_epAddr && (usb_endpoint_is_int_in(ep_desc))) {
+                       ksb->in_epAddr = ep_desc->bEndpointAddress;
+                       ksb->period = ep_desc->bInterval;
+               }
+
+               if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
+                       ksb->out_epAddr = ep_desc->bEndpointAddress;
+       }
+
+       if (!(ksb->in_epAddr && ksb->out_epAddr)) {
+               dev_err(&udev->dev,
+                       "could not find bulk in and bulk out endpoints");
+               usb_put_dev(ksb->udev);
+               ksb->ifc = NULL;
+               if (free_mdev)
+                       kfree(mdev);
+               return -ENODEV;
+       }
+
+       ksb->in_pipe = ksb->period ?
+               usb_rcvintpipe(ksb->udev, ksb->in_epAddr) :
+               usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
+
+       ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
+
+       usb_set_intfdata(ifc, ksb);
+       set_bit(USB_DEV_CONNECTED, &ksb->flags);
+       atomic_set(&ksb->tx_pending_cnt, 0);
+       atomic_set(&ksb->rx_pending_cnt, 0);
+
+       dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
+
+       /*free up stale buffers if any from previous disconnect*/
+       spin_lock_irqsave(&ksb->lock, flags);
+       while (!list_empty(&ksb->to_ks_list)) {
+               pkt = list_first_entry(&ksb->to_ks_list,
+                               struct data_pkt, list);
+               list_del_init(&pkt->list);
+               ksb_free_data_pkt(pkt);
+       }
+       while (!list_empty(&ksb->to_mdm_list)) {
+               pkt = list_first_entry(&ksb->to_mdm_list,
+                               struct data_pkt, list);
+               list_del_init(&pkt->list);
+               ksb_free_data_pkt(pkt);
+       }
+       spin_unlock_irqrestore(&ksb->lock, flags);
+
+       ret = alloc_chrdev_region(&ksb->cdev_start_no, 0, 1, mdev->name);
+       if (ret < 0) {
+               dbg_log_event(ksb, "chr reg failed", ret, 0);
+               goto fail_chrdev_region;
+       }
+
+       ksb->class = class_create(THIS_MODULE, mdev->name);
+       if (IS_ERR(ksb->class)) {
+               dbg_log_event(ksb, "clscr failed", PTR_ERR(ksb->class), 0);
+               goto fail_class_create;
+       }
+
+       cdev_init(&ksb->cdev, &ksb_fops);
+       ksb->cdev.owner = THIS_MODULE;
+
+       ret = cdev_add(&ksb->cdev, ksb->cdev_start_no, 1);
+       if (ret < 0) {
+               dbg_log_event(ksb, "cdev_add failed", ret, 0);
+               goto fail_class_create;
+       }
+
+       ksb->device = device_create(ksb->class, &udev->dev, ksb->cdev_start_no,
+                               NULL, mdev->name);
+       if (IS_ERR(ksb->device)) {
+               dbg_log_event(ksb, "devcrfailed", PTR_ERR(ksb->device), 0);
+               goto fail_device_create;
+       }
+
+       if (device_can_wakeup(&ksb->udev->dev))
+               ifc->needs_remote_wakeup = 1;
+
+       if (free_mdev)
+               kfree(mdev);
+       dev_dbg(&udev->dev, "usb dev connected");
+
+       return 0;
+
+fail_device_create:
+       cdev_del(&ksb->cdev);
+fail_class_create:
+       unregister_chrdev_region(ksb->cdev_start_no, 1);
+fail_chrdev_region:
+       usb_set_intfdata(ifc, NULL);
+       clear_bit(USB_DEV_CONNECTED, &ksb->flags);
+
+       if (free_mdev)
+               kfree(mdev);
+
+       return -ENODEV;
+
+}
+
+static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
+{
+       struct ks_bridge *ksb = usb_get_intfdata(ifc);
+       unsigned long flags;
+
+       dbg_log_event(ksb, "SUSPEND", 0, 0);
+
+       if (pm_runtime_autosuspend_expiration(&ksb->udev->dev)) {
+               dbg_log_event(ksb, "SUSP ABORT-TimeCheck", 0, 0);
+               return -EBUSY;
+       }
+
+       usb_kill_anchored_urbs(&ksb->submitted);
+
+       spin_lock_irqsave(&ksb->lock, flags);
+       if (!list_empty(&ksb->to_ks_list)) {
+               spin_unlock_irqrestore(&ksb->lock, flags);
+               dbg_log_event(ksb, "SUSPEND ABORT", 0, 0);
+               /*
+                * Now wakeup the reader process and queue
+                * Rx URBs for more data.
+                */
+               wake_up(&ksb->ks_wait_q);
+               queue_work(ksb->wq, &ksb->start_rx_work);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&ksb->lock, flags);
+
+       return 0;
+}
+
+static int ksb_usb_resume(struct usb_interface *ifc)
+{
+       struct ks_bridge *ksb = usb_get_intfdata(ifc);
+
+       dbg_log_event(ksb, "RESUME", 0, 0);
+
+       if (test_bit(FILE_OPENED, &ksb->flags))
+               queue_work(ksb->wq, &ksb->start_rx_work);
+
+       return 0;
+}
+
+static void ksb_usb_disconnect(struct usb_interface *ifc)
+{
+       struct ks_bridge *ksb = usb_get_intfdata(ifc);
+       unsigned long flags;
+       struct data_pkt *pkt;
+
+       dbg_log_event(ksb, "PID-DETACH", 0, 0);
+
+       clear_bit(USB_DEV_CONNECTED, &ksb->flags);
+       wake_up(&ksb->ks_wait_q);
+       cancel_work_sync(&ksb->to_mdm_work);
+       cancel_work_sync(&ksb->start_rx_work);
+
+       device_destroy(ksb->class, ksb->cdev_start_no);
+       cdev_del(&ksb->cdev);
+       class_destroy(ksb->class);
+       unregister_chrdev_region(ksb->cdev_start_no, 1);
+
+       usb_kill_anchored_urbs(&ksb->submitted);
+
+       wait_event_interruptible_timeout(
+                                       ksb->pending_urb_wait,
+                                       !atomic_read(&ksb->tx_pending_cnt) &&
+                                       !atomic_read(&ksb->rx_pending_cnt),
+                                       msecs_to_jiffies(PENDING_URB_TIMEOUT));
+
+       spin_lock_irqsave(&ksb->lock, flags);
+       while (!list_empty(&ksb->to_ks_list)) {
+               pkt = list_first_entry(&ksb->to_ks_list,
+                               struct data_pkt, list);
+               list_del_init(&pkt->list);
+               ksb_free_data_pkt(pkt);
+       }
+       while (!list_empty(&ksb->to_mdm_list)) {
+               pkt = list_first_entry(&ksb->to_mdm_list,
+                               struct data_pkt, list);
+               list_del_init(&pkt->list);
+               ksb_free_data_pkt(pkt);
+       }
+       spin_unlock_irqrestore(&ksb->lock, flags);
+
+       ifc->needs_remote_wakeup = 0;
+       usb_put_dev(ksb->udev);
+       ksb->ifc = NULL;
+       usb_set_intfdata(ifc, NULL);
+}
+
+static struct usb_driver ksb_usb_driver = {
+       .name =         "ks_bridge",
+       .probe =        ksb_usb_probe,
+       .disconnect =   ksb_usb_disconnect,
+       .suspend =      ksb_usb_suspend,
+       .resume =       ksb_usb_resume,
+       .reset_resume = ksb_usb_resume,
+       .id_table =     ksb_usb_ids,
+       .supports_autosuspend = 1,
+};
+
+static int ksb_debug_show(struct seq_file *s, void *unused)
+{
+       unsigned long           flags;
+       struct ks_bridge        *ksb = s->private;
+       int                     i;
+
+       read_lock_irqsave(&ksb->dbg_lock, flags);
+       for (i = 0; i < DBG_MAX_MSG; i++) {
+               if (i == (ksb->dbg_idx - 1))
+                       seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
+               else
+                       seq_printf(s, "%s\n", ksb->dbgbuf[i]);
+       }
+       read_unlock_irqrestore(&ksb->dbg_lock, flags);
+
+       return 0;
+}
+
+static int ksb_debug_open(struct inode *ip, struct file *fp)
+{
+       return single_open(fp, ksb_debug_show, ip->i_private);
+
+       return 0;
+}
+
+static const struct file_operations dbg_fops = {
+       .open = ksb_debug_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static struct dentry *dbg_dir;
+
+static int __init ksb_init(void)
+{
+       struct ks_bridge *ksb;
+       int num_instances = 0;
+       int ret = 0;
+       int i;
+
+       dbg_dir = debugfs_create_dir("ks_bridge", NULL);
+       if (IS_ERR(dbg_dir))
+               pr_err("unable to create debug dir");
+
+       for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
+               ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
+               if (!ksb) {
+                       pr_err("unable to allocat mem for ks_bridge");
+                       ret =  -ENOMEM;
+                       goto dev_free;
+               }
+               __ksb[i] = ksb;
+
+               ksb->name = kasprintf(GFP_KERNEL, "ks_usb_bridge.%i", i);
+               if (!ksb->name) {
+                       pr_info("unable to allocate name");
+                       kfree(ksb);
+                       ret = -ENOMEM;
+                       goto dev_free;
+               }
+
+               spin_lock_init(&ksb->lock);
+               INIT_LIST_HEAD(&ksb->to_mdm_list);
+               INIT_LIST_HEAD(&ksb->to_ks_list);
+               init_waitqueue_head(&ksb->ks_wait_q);
+               init_waitqueue_head(&ksb->pending_urb_wait);
+               ksb->wq = create_singlethread_workqueue(ksb->name);
+               if (!ksb->wq) {
+                       pr_err("unable to allocate workqueue");
+                       kfree(ksb->name);
+                       kfree(ksb);
+                       ret = -ENOMEM;
+                       goto dev_free;
+               }
+
+               INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
+               INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
+               init_usb_anchor(&ksb->submitted);
+
+               ksb->dbg_idx = 0;
+               ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
+
+               if (!IS_ERR(dbg_dir))
+                       debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
+                                       ksb, &dbg_fops);
+
+               num_instances++;
+       }
+
+       ret = usb_register(&ksb_usb_driver);
+       if (ret) {
+               pr_err("unable to register ks bridge driver");
+               goto dev_free;
+       }
+
+       pr_info("init done");
+
+       return 0;
+
+dev_free:
+       if (!IS_ERR(dbg_dir))
+               debugfs_remove_recursive(dbg_dir);
+
+       for (i = 0; i < num_instances; i++) {
+               ksb = __ksb[i];
+
+               destroy_workqueue(ksb->wq);
+               kfree(ksb->name);
+               kfree(ksb);
+       }
+
+       return ret;
+
+}
+
+static void __exit ksb_exit(void)
+{
+       struct ks_bridge *ksb;
+       int i;
+
+       if (!IS_ERR(dbg_dir))
+               debugfs_remove_recursive(dbg_dir);
+
+       usb_deregister(&ksb_usb_driver);
+
+       for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
+               ksb = __ksb[i];
+
+               destroy_workqueue(ksb->wq);
+               kfree(ksb->name);
+               kfree(ksb);
+       }
+}
+
+module_init(ksb_init);
+module_exit(ksb_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
index c76ca5a..055c620 100644 (file)
@@ -2365,7 +2365,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
        pd->vbus_present = val.intval;
 
        ret = power_supply_get_property(pd->usb_psy,
-                       POWER_SUPPLY_PROP_TYPE, &val);
+                       POWER_SUPPLY_PROP_REAL_TYPE, &val);
        if (ret) {
                usbpd_err(&pd->dev, "Unable to read USB TYPE: %d\n", ret);
                return ret;
index 9982cb1..830e2fd 100644 (file)
@@ -562,8 +562,9 @@ static long vfio_pci_ioctl(void *device_data,
 
        } else if (cmd == VFIO_DEVICE_SET_IRQS) {
                struct vfio_irq_set hdr;
+               size_t size;
                u8 *data = NULL;
-               int ret = 0;
+               int max, ret = 0;
 
                minsz = offsetofend(struct vfio_irq_set, count);
 
@@ -571,23 +572,31 @@ static long vfio_pci_ioctl(void *device_data,
                        return -EFAULT;
 
                if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
+                   hdr.count >= (U32_MAX - hdr.start) ||
                    hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
                                  VFIO_IRQ_SET_ACTION_TYPE_MASK))
                        return -EINVAL;
 
-               if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
-                       size_t size;
-                       int max = vfio_pci_get_irq_count(vdev, hdr.index);
+               max = vfio_pci_get_irq_count(vdev, hdr.index);
+               if (hdr.start >= max || hdr.start + hdr.count > max)
+                       return -EINVAL;
 
-                       if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
-                               size = sizeof(uint8_t);
-                       else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
-                               size = sizeof(int32_t);
-                       else
-                               return -EINVAL;
+               switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
+               case VFIO_IRQ_SET_DATA_NONE:
+                       size = 0;
+                       break;
+               case VFIO_IRQ_SET_DATA_BOOL:
+                       size = sizeof(uint8_t);
+                       break;
+               case VFIO_IRQ_SET_DATA_EVENTFD:
+                       size = sizeof(int32_t);
+                       break;
+               default:
+                       return -EINVAL;
+               }
 
-                       if (hdr.argsz - minsz < hdr.count * size ||
-                           hdr.start >= max || hdr.start + hdr.count > max)
+               if (size) {
+                       if (hdr.argsz - minsz < hdr.count * size)
                                return -EINVAL;
 
                        data = memdup_user((void __user *)(arg + minsz),
index 20e9a86..5c8f767 100644 (file)
@@ -255,7 +255,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
        if (!is_irq_none(vdev))
                return -EINVAL;
 
-       vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+       vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
        if (!vdev->ctx)
                return -ENOMEM;
 
index f6f65cc..238e851 100644 (file)
@@ -126,7 +126,11 @@ obj-y                             += omap2/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)         += mb862xx/
-obj-$(CONFIG_FB_MSM)              += msm/
+ifeq ($(CONFIG_FB_MSM),y)
+obj-y                             += msm/
+else
+obj-$(CONFIG_MSM_DBA)             += msm/msm_dba/
+endif
 obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
 obj-$(CONFIG_FB_JZ4740)                  += jz4740_fb.o
 obj-$(CONFIG_FB_PUV3_UNIGFX)      += fb-puv3.o
index 5fff312..03df17d 100644 (file)
@@ -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
@@ -115,4 +115,13 @@ int mdss_dsi_phy_v3_wait_for_lanes_stop_state(struct mdss_dsi_ctrl_pdata *ctrl,
  * assumes that the link and core clocks are already on.
  */
 int mdss_dsi_phy_v3_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, bool enable);
+
+/**
+ * mdss_dsi_phy_v3_idle_pc_exit() - Called after Idle Power Collapse exit
+ * @ctrl: pointer to DSI controller structure
+ *
+ * This function is called after Idle Power Collapse, so driver
+ * can perform any sequence required after the Idle PC exit.
+ */
+void mdss_dsi_phy_v3_idle_pc_exit(struct mdss_dsi_ctrl_pdata *ctrl);
 #endif /* MDSS_DSI_PHY_H */
index 992fd51..bb9dbfa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -327,6 +327,7 @@ int mdss_dsi_phy_v3_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, bool enable)
                 */
                DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL3,
                        active_lanes);
+               usleep_range(5, 15);
 
                DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL3, 0);
 
@@ -340,6 +341,20 @@ error:
        return rc;
 }
 
+void mdss_dsi_phy_v3_idle_pc_exit(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+       u32 val = BIT(5);
+       u32 data;
+
+       /* Reset phy pll after idle pc exit */
+       data = DSI_PHY_R32(ctrl->phy_io.base, CMN_CTRL_1);
+       DSI_PHY_W32(ctrl->phy_io.base, CMN_CTRL_1, data | val);
+       usleep_range(10, 15);
+
+       data = DSI_PHY_R32(ctrl->phy_io.base, CMN_CTRL_1);
+       data &= ~(BIT(5));
+       DSI_PHY_W32(ctrl->phy_io.base, CMN_CTRL_1, data);
+}
 
 int mdss_dsi_phy_v3_shutdown(struct mdss_dsi_ctrl_pdata *ctrl)
 {
index 09a3422..5e96a08 100644 (file)
@@ -3035,6 +3035,12 @@ int mdss_mdp_layer_pre_commit_wfd(struct msm_fb_data_type *mfd,
                wfd = mdp5_data->wfd;
                output_layer = commit->output_layer;
 
+               if (output_layer->buffer.plane_count > MAX_PLANES) {
+                       pr_err("Output buffer plane_count exceeds MAX_PLANES limit:%d\n",
+                                       output_layer->buffer.plane_count);
+                       return -EINVAL;
+               }
+
                data = mdss_mdp_wfd_add_data(wfd, output_layer);
                if (IS_ERR_OR_NULL(data))
                        return PTR_ERR(data);
index 71a07f6..7868dc0 100644 (file)
@@ -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
@@ -322,6 +322,12 @@ int mdss_mdp_wb_import_data(struct device *device,
        if (wfd_data->layer.flags & MDP_LAYER_SECURE_SESSION)
                flags = MDP_SECURE_OVERLAY_SESSION;
 
+       if (buffer->plane_count > MAX_PLANES) {
+               pr_err("buffer plane_count exceeds MAX_PLANES limit:%d",
+                               buffer->plane_count);
+               return -EINVAL;
+       }
+
        memset(planes, 0, sizeof(planes));
 
        for (i = 0; i < buffer->plane_count; i++) {
index fdd1c01..399a12e 100644 (file)
@@ -501,6 +501,12 @@ static int mdss_rotator_import_buffer(struct mdp_layer_buffer *buffer,
 
        memset(planes, 0, sizeof(planes));
 
+       if (buffer->plane_count > MAX_PLANES) {
+               pr_err("buffer plane_count exceeds MAX_PLANES limit:%d\n",
+                               buffer->plane_count);
+               return -EINVAL;
+       }
+
        for (i = 0; i < buffer->plane_count; i++) {
                planes[i].memory_id = buffer->planes[i].fd;
                planes[i].offset = buffer->planes[i].offset;
@@ -2104,6 +2110,20 @@ struct mdss_rot_entry_container *mdss_rotator_req_init(
        struct mdss_rot_entry_container *req;
        int size, i;
 
+       /*
+        * Check input and output plane_count from each given item
+        * are within the MAX_PLANES limit
+        */
+       for (i = 0 ; i < count; i++) {
+               if ((items[i].input.plane_count > MAX_PLANES) ||
+                               (items[i].output.plane_count > MAX_PLANES)) {
+                       pr_err("Input/Output plane_count exceeds MAX_PLANES limit, input:%d, output:%d\n",
+                                       items[i].input.plane_count,
+                                       items[i].output.plane_count);
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
        size = sizeof(struct mdss_rot_entry_container);
        size += sizeof(struct mdss_rot_entry) * count;
        req = devm_kzalloc(&mgr->pdev->dev, size, GFP_KERNEL);
index 8503d84..63e178d 100644 (file)
@@ -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
@@ -31,7 +31,7 @@
 
 #define ADV7533_REG_CHIP_REVISION (0x00)
 #define ADV7533_DSI_CEC_I2C_ADDR_REG (0xE1)
-#define ADV7533_RESET_DELAY (100)
+#define ADV7533_RESET_DELAY (10)
 
 #define PINCTRL_STATE_ACTIVE    "pmx_adv7533_active"
 #define PINCTRL_STATE_SUSPEND   "pmx_adv7533_suspend"
@@ -1539,14 +1539,14 @@ exit:
 static int adv7533_video_on(void *client, bool on,
        struct msm_dba_video_cfg *cfg, u32 flags)
 {
-       int ret = -EINVAL;
+       int ret = 0;
        u8 lanes;
        u8 reg_val = 0;
        struct adv7533 *pdata = adv7533_get_platform_data(client);
 
        if (!pdata || !cfg) {
                pr_err("%s: invalid platform data\n", __func__);
-               return ret;
+               return -EINVAL;
        }
 
        mutex_lock(&pdata->ops_mutex);
index f6128ae..a0b45bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 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
@@ -123,7 +123,7 @@ int msm_dba_helper_i2c_write_byte(struct i2c_client *client,
                return -EINVAL;
        }
 
-       pr_debug("%s: [%s:0x02%x] : W[0x%02x, 0x%02x]\n", __func__,
+       pr_debug("%s: [%s:0x%02x] : W[0x%02x, 0x%02x]\n", __func__,
                 client->name, addr, reg, val);
        client->addr = addr;
 
index c81d45b..690d74f 100644 (file)
@@ -2137,6 +2137,20 @@ error:
 }
 
 /**
+ * mdss_dsi_phy_idle_pc_exit() - Called after exit Idle PC
+ * @ctrl: pointer to DSI controller structure
+ *
+ * Perform any programming needed after Idle PC exit.
+ */
+static int mdss_dsi_phy_idle_pc_exit(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+       if (ctrl->shared_data->phy_rev == DSI_PHY_REV_30)
+               mdss_dsi_phy_v3_idle_pc_exit(ctrl);
+
+       return 0;
+}
+
+/**
  * mdss_dsi_clamp_ctrl_default() - Program DSI clamps
  * @ctrl: pointer to DSI controller structure
  * @enable: true to enable clamps, false to disable clamps
@@ -2700,5 +2714,10 @@ int mdss_dsi_pre_clkon_cb(void *priv,
                }
        }
 
+       if ((clk_type & MDSS_DSI_LINK_CLK) &&
+               (new_state == MDSS_DSI_CLK_ON) &&
+               !ctrl->panel_data.panel_info.cont_splash_enabled)
+               mdss_dsi_phy_idle_pc_exit(ctrl);
+
        return rc;
 }
index 0567d51..ea2f19f 100644 (file)
@@ -644,7 +644,6 @@ static void xenfb_backend_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateInitWait:
-InitWait:
                xenbus_switch_state(dev, XenbusStateConnected);
                break;
 
@@ -655,7 +654,8 @@ InitWait:
                 * get Connected twice here.
                 */
                if (dev->state != XenbusStateConnected)
-                       goto InitWait; /* no InitWait seen yet, fudge it */
+                       /* no InitWait seen yet, fudge it */
+                       xenbus_switch_state(dev, XenbusStateConnected);
 
                if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
                                 "request-update", "%d", &val) < 0)
index 3b54070..dee2375 100644 (file)
@@ -41,7 +41,7 @@ obj-$(CONFIG_COMPAT_BINFMT_ELF)       += compat_binfmt_elf.o
 obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o
 obj-$(CONFIG_BINFMT_FLAT)      += binfmt_flat.o
 
-obj-$(CONFIG_FS_MBCACHE)       += mbcache.o
+obj-$(CONFIG_FS_MBCACHE)       += mbcache.o mbcache2.o
 obj-$(CONFIG_FS_POSIX_ACL)     += posix_acl.o
 obj-$(CONFIG_NFS_COMMON)       += nfs_common/
 obj-$(CONFIG_COREDUMP)         += coredump.o
index b768836..94906aa 100644 (file)
@@ -906,7 +906,6 @@ struct cifs_tcon {
        bool use_persistent:1; /* use persistent instead of durable handles */
 #ifdef CONFIG_CIFS_SMB2
        bool print:1;           /* set if connection to printer share */
-       bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
        __le32 capabilities;
        __u32 share_flags;
        __u32 maximal_access;
index 72f270d..a0c0a49 100644 (file)
@@ -2545,7 +2545,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                wdata->credits = credits;
 
                if (!wdata->cfile->invalidHandle ||
-                   !cifs_reopen_file(wdata->cfile, false))
+                   !(rc = cifs_reopen_file(wdata->cfile, false)))
                        rc = server->ops->async_writev(wdata,
                                        cifs_uncached_writedata_release);
                if (rc) {
@@ -2958,7 +2958,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                rdata->credits = credits;
 
                if (!rdata->cfile->invalidHandle ||
-                   !cifs_reopen_file(rdata->cfile, true))
+                   !(rc = cifs_reopen_file(rdata->cfile, true)))
                        rc = server->ops->async_readv(rdata);
 error:
                if (rc) {
@@ -3544,7 +3544,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                }
 
                if (!rdata->cfile->invalidHandle ||
-                   !cifs_reopen_file(rdata->cfile, true))
+                   !(rc = cifs_reopen_file(rdata->cfile, true)))
                        rc = server->ops->async_readv(rdata);
                if (rc) {
                        add_credits_and_wake_if(server, rdata->credits, 0);
index fc537c2..87b87e0 100644 (file)
@@ -1015,6 +1015,15 @@ cifs_dir_needs_close(struct cifsFileInfo *cfile)
        return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
 }
 
+static bool
+cifs_can_echo(struct TCP_Server_Info *server)
+{
+       if (server->tcpStatus == CifsGood)
+               return true;
+
+       return false;
+}
+
 struct smb_version_operations smb1_operations = {
        .send_cancel = send_nt_cancel,
        .compare_fids = cifs_compare_fids,
@@ -1049,6 +1058,7 @@ struct smb_version_operations smb1_operations = {
        .get_dfs_refer = CIFSGetDFSRefer,
        .qfs_tcon = cifs_qfs_tcon,
        .is_path_accessible = cifs_is_path_accessible,
+       .can_echo = cifs_can_echo,
        .query_path_info = cifs_query_path_info,
        .query_file_info = cifs_query_file_info,
        .get_srv_inum = cifs_get_srv_inum,
index 2fa754c..6cb2603 100644 (file)
@@ -932,9 +932,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        else
                return -EIO;
 
-       if (tcon && tcon->bad_network_name)
-               return -ENOENT;
-
        if ((tcon && tcon->seal) &&
            ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
                cifs_dbg(VFS, "encryption requested but no server support");
@@ -952,6 +949,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
                return -EINVAL;
        }
 
+       /* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
+       if (tcon)
+               tcon->tid = 0;
+
        rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req);
        if (rc) {
                kfree(unc_path);
@@ -1032,8 +1033,6 @@ tcon_exit:
 tcon_error_exit:
        if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
                cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-               if (tcon)
-                       tcon->bad_network_name = true;
        }
        goto tcon_exit;
 }
index b591e67..85f7a28 100644 (file)
@@ -168,14 +168,13 @@ void ecryptfs_put_lower_file(struct inode *inode)
                                get_events()->is_hw_crypt_cb())
                        clear_cache_needed = true;
 
+               filemap_write_and_wait(inode->i_mapping);
                if (clear_cache_needed) {
                        ret = vfs_fsync(inode_info->lower_file, false);
 
                        if (ret)
                                pr_err("failed to sync file ret = %d.\n", ret);
                }
-
-               filemap_write_and_wait(inode->i_mapping);
                fput(inode_info->lower_file);
                inode_info->lower_file = NULL;
                mutex_unlock(&inode_info->lower_file_mutex);
index 4c69c94..f98ce7e 100644 (file)
@@ -61,6 +61,8 @@ struct ext2_block_alloc_info {
 #define rsv_start rsv_window._rsv_start
 #define rsv_end rsv_window._rsv_end
 
+struct mb2_cache;
+
 /*
  * second extended-fs super-block data in memory
  */
@@ -111,6 +113,7 @@ struct ext2_sb_info {
         * of the mount options.
         */
        spinlock_t s_lock;
+       struct mb2_cache *s_mb_cache;
 };
 
 static inline spinlock_t *
index 748d35a..111a317 100644 (file)
@@ -131,7 +131,10 @@ static void ext2_put_super (struct super_block * sb)
 
        dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 
-       ext2_xattr_put_super(sb);
+       if (sbi->s_mb_cache) {
+               ext2_xattr_destroy_cache(sbi->s_mb_cache);
+               sbi->s_mb_cache = NULL;
+       }
        if (!(sb->s_flags & MS_RDONLY)) {
                struct ext2_super_block *es = sbi->s_es;
 
@@ -1104,6 +1107,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                ext2_msg(sb, KERN_ERR, "error: insufficient memory");
                goto failed_mount3;
        }
+
+#ifdef CONFIG_EXT2_FS_XATTR
+       sbi->s_mb_cache = ext2_xattr_create_cache();
+       if (!sbi->s_mb_cache) {
+               ext2_msg(sb, KERN_ERR, "Failed to create an mb_cache");
+               goto failed_mount3;
+       }
+#endif
        /*
         * set up enough so that it can read an inode
         */
@@ -1149,6 +1160,8 @@ cantfind_ext2:
                        sb->s_id);
        goto failed_mount;
 failed_mount3:
+       if (sbi->s_mb_cache)
+               ext2_xattr_destroy_cache(sbi->s_mb_cache);
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -1555,20 +1568,17 @@ MODULE_ALIAS_FS("ext2");
 
 static int __init init_ext2_fs(void)
 {
-       int err = init_ext2_xattr();
-       if (err)
-               return err;
+       int err;
+
        err = init_inodecache();
        if (err)
-               goto out1;
+               return err;
         err = register_filesystem(&ext2_fs_type);
        if (err)
                goto out;
        return 0;
 out:
        destroy_inodecache();
-out1:
-       exit_ext2_xattr();
        return err;
 }
 
@@ -1576,7 +1586,6 @@ static void __exit exit_ext2_fs(void)
 {
        unregister_filesystem(&ext2_fs_type);
        destroy_inodecache();
-       exit_ext2_xattr();
 }
 
 MODULE_AUTHOR("Remy Card and others");
index fa70848..24736c8 100644 (file)
@@ -56,7 +56,7 @@
 #include <linux/buffer_head.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/mbcache.h>
+#include <linux/mbcache2.h>
 #include <linux/quotaops.h>
 #include <linux/rwsem.h>
 #include <linux/security.h>
 static int ext2_xattr_set2(struct inode *, struct buffer_head *,
                           struct ext2_xattr_header *);
 
-static int ext2_xattr_cache_insert(struct buffer_head *);
+static int ext2_xattr_cache_insert(struct mb2_cache *, struct buffer_head *);
 static struct buffer_head *ext2_xattr_cache_find(struct inode *,
                                                 struct ext2_xattr_header *);
 static void ext2_xattr_rehash(struct ext2_xattr_header *,
                              struct ext2_xattr_entry *);
 
-static struct mb_cache *ext2_xattr_cache;
-
 static const struct xattr_handler *ext2_xattr_handler_map[] = {
        [EXT2_XATTR_INDEX_USER]              = &ext2_xattr_user_handler,
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
@@ -154,6 +152,7 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name,
        size_t name_len, size;
        char *end;
        int error;
+       struct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
 
        ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
                  name_index, name, buffer, (long)buffer_size);
@@ -198,7 +197,7 @@ bad_block:  ext2_error(inode->i_sb, "ext2_xattr_get",
                        goto found;
                entry = next;
        }
-       if (ext2_xattr_cache_insert(bh))
+       if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
                ea_idebug(inode, "cache insert failed");
        error = -ENODATA;
        goto cleanup;
@@ -211,7 +210,7 @@ found:
            le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
                goto bad_block;
 
-       if (ext2_xattr_cache_insert(bh))
+       if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
                ea_idebug(inode, "cache insert failed");
        if (buffer) {
                error = -ERANGE;
@@ -249,6 +248,7 @@ ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
        char *end;
        size_t rest = buffer_size;
        int error;
+       struct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
 
        ea_idebug(inode, "buffer=%p, buffer_size=%ld",
                  buffer, (long)buffer_size);
@@ -283,7 +283,7 @@ bad_block:  ext2_error(inode->i_sb, "ext2_xattr_list",
                        goto bad_block;
                entry = next;
        }
-       if (ext2_xattr_cache_insert(bh))
+       if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
                ea_idebug(inode, "cache insert failed");
 
        /* list the attribute names */
@@ -480,22 +480,23 @@ bad_block:                ext2_error(sb, "ext2_xattr_set",
        /* Here we know that we can set the new attribute. */
 
        if (header) {
-               struct mb_cache_entry *ce;
-
                /* assert(header == HDR(bh)); */
-               ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev,
-                                       bh->b_blocknr);
                lock_buffer(bh);
                if (header->h_refcount == cpu_to_le32(1)) {
+                       __u32 hash = le32_to_cpu(header->h_hash);
+
                        ea_bdebug(bh, "modifying in-place");
-                       if (ce)
-                               mb_cache_entry_free(ce);
+                       /*
+                        * This must happen under buffer lock for
+                        * ext2_xattr_set2() to reliably detect modified block
+                        */
+                       mb2_cache_entry_delete_block(EXT2_SB(sb)->s_mb_cache,
+                                                    hash, bh->b_blocknr);
+
                        /* keep the buffer locked while modifying it. */
                } else {
                        int offset;
 
-                       if (ce)
-                               mb_cache_entry_release(ce);
                        unlock_buffer(bh);
                        ea_bdebug(bh, "cloning");
                        header = kmalloc(bh->b_size, GFP_KERNEL);
@@ -623,6 +624,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
        struct super_block *sb = inode->i_sb;
        struct buffer_head *new_bh = NULL;
        int error;
+       struct mb2_cache *ext2_mb_cache = EXT2_SB(sb)->s_mb_cache;
 
        if (header) {
                new_bh = ext2_xattr_cache_find(inode, header);
@@ -650,7 +652,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
                           don't need to change the reference count. */
                        new_bh = old_bh;
                        get_bh(new_bh);
-                       ext2_xattr_cache_insert(new_bh);
+                       ext2_xattr_cache_insert(ext2_mb_cache, new_bh);
                } else {
                        /* We need to allocate a new block */
                        ext2_fsblk_t goal = ext2_group_first_block_no(sb,
@@ -671,7 +673,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
                        memcpy(new_bh->b_data, header, new_bh->b_size);
                        set_buffer_uptodate(new_bh);
                        unlock_buffer(new_bh);
-                       ext2_xattr_cache_insert(new_bh);
+                       ext2_xattr_cache_insert(ext2_mb_cache, new_bh);
                        
                        ext2_xattr_update_super_block(sb);
                }
@@ -704,19 +706,21 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
 
        error = 0;
        if (old_bh && old_bh != new_bh) {
-               struct mb_cache_entry *ce;
-
                /*
                 * If there was an old block and we are no longer using it,
                 * release the old block.
                 */
-               ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev,
-                                       old_bh->b_blocknr);
                lock_buffer(old_bh);
                if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
+                       __u32 hash = le32_to_cpu(HDR(old_bh)->h_hash);
+
+                       /*
+                        * This must happen under buffer lock for
+                        * ext2_xattr_set2() to reliably detect freed block
+                        */
+                       mb2_cache_entry_delete_block(ext2_mb_cache,
+                                                    hash, old_bh->b_blocknr);
                        /* Free the old block. */
-                       if (ce)
-                               mb_cache_entry_free(ce);
                        ea_bdebug(old_bh, "freeing");
                        ext2_free_blocks(inode, old_bh->b_blocknr, 1);
                        mark_inode_dirty(inode);
@@ -727,8 +731,6 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
                } else {
                        /* Decrement the refcount only. */
                        le32_add_cpu(&HDR(old_bh)->h_refcount, -1);
-                       if (ce)
-                               mb_cache_entry_release(ce);
                        dquot_free_block_nodirty(inode, 1);
                        mark_inode_dirty(inode);
                        mark_buffer_dirty(old_bh);
@@ -754,7 +756,6 @@ void
 ext2_xattr_delete_inode(struct inode *inode)
 {
        struct buffer_head *bh = NULL;
-       struct mb_cache_entry *ce;
 
        down_write(&EXT2_I(inode)->xattr_sem);
        if (!EXT2_I(inode)->i_file_acl)
@@ -774,19 +775,22 @@ ext2_xattr_delete_inode(struct inode *inode)
                        EXT2_I(inode)->i_file_acl);
                goto cleanup;
        }
-       ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr);
        lock_buffer(bh);
        if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
-               if (ce)
-                       mb_cache_entry_free(ce);
+               __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
+
+               /*
+                * This must happen under buffer lock for ext2_xattr_set2() to
+                * reliably detect freed block
+                */
+               mb2_cache_entry_delete_block(EXT2_SB(inode->i_sb)->s_mb_cache,
+                                            hash, bh->b_blocknr);
                ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);
                get_bh(bh);
                bforget(bh);
                unlock_buffer(bh);
        } else {
                le32_add_cpu(&HDR(bh)->h_refcount, -1);
-               if (ce)
-                       mb_cache_entry_release(ce);
                ea_bdebug(bh, "refcount now=%d",
                        le32_to_cpu(HDR(bh)->h_refcount));
                unlock_buffer(bh);
@@ -803,18 +807,6 @@ cleanup:
 }
 
 /*
- * ext2_xattr_put_super()
- *
- * This is called when a file system is unmounted.
- */
-void
-ext2_xattr_put_super(struct super_block *sb)
-{
-       mb_cache_shrink(sb->s_bdev);
-}
-
-
-/*
  * ext2_xattr_cache_insert()
  *
  * Create a new entry in the extended attribute cache, and insert
@@ -823,28 +815,20 @@ ext2_xattr_put_super(struct super_block *sb)
  * Returns 0, or a negative error number on failure.
  */
 static int
-ext2_xattr_cache_insert(struct buffer_head *bh)
+ext2_xattr_cache_insert(struct mb2_cache *cache, struct buffer_head *bh)
 {
        __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
-       struct mb_cache_entry *ce;
        int error;
 
-       ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS);
-       if (!ce)
-               return -ENOMEM;
-       error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
+       error = mb2_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr);
        if (error) {
-               mb_cache_entry_free(ce);
                if (error == -EBUSY) {
                        ea_bdebug(bh, "already in cache (%d cache entries)",
                                atomic_read(&ext2_xattr_cache->c_entry_count));
                        error = 0;
                }
-       } else {
-               ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
-                         atomic_read(&ext2_xattr_cache->c_entry_count));
-               mb_cache_entry_release(ce);
-       }
+       } else
+               ea_bdebug(bh, "inserting [%x]", (int)hash);
        return error;
 }
 
@@ -900,23 +884,17 @@ static struct buffer_head *
 ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
 {
        __u32 hash = le32_to_cpu(header->h_hash);
-       struct mb_cache_entry *ce;
+       struct mb2_cache_entry *ce;
+       struct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
 
        if (!header->h_hash)
                return NULL;  /* never share */
        ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
 again:
-       ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev,
-                                      hash);
+       ce = mb2_cache_entry_find_first(ext2_mb_cache, hash);
        while (ce) {
                struct buffer_head *bh;
 
-               if (IS_ERR(ce)) {
-                       if (PTR_ERR(ce) == -EAGAIN)
-                               goto again;
-                       break;
-               }
-
                bh = sb_bread(inode->i_sb, ce->e_block);
                if (!bh) {
                        ext2_error(inode->i_sb, "ext2_xattr_cache_find",
@@ -924,7 +902,21 @@ again:
                                inode->i_ino, (unsigned long) ce->e_block);
                } else {
                        lock_buffer(bh);
-                       if (le32_to_cpu(HDR(bh)->h_refcount) >
+                       /*
+                        * We have to be careful about races with freeing or
+                        * rehashing of xattr block. Once we hold buffer lock
+                        * xattr block's state is stable so we can check
+                        * whether the block got freed / rehashed or not.
+                        * Since we unhash mbcache entry under buffer lock when
+                        * freeing / rehashing xattr block, checking whether
+                        * entry is still hashed is reliable.
+                        */
+                       if (hlist_bl_unhashed(&ce->e_hash_list)) {
+                               mb2_cache_entry_put(ext2_mb_cache, ce);
+                               unlock_buffer(bh);
+                               brelse(bh);
+                               goto again;
+                       } else if (le32_to_cpu(HDR(bh)->h_refcount) >
                                   EXT2_XATTR_REFCOUNT_MAX) {
                                ea_idebug(inode, "block %ld refcount %d>%d",
                                          (unsigned long) ce->e_block,
@@ -933,13 +925,14 @@ again:
                        } else if (!ext2_xattr_cmp(header, HDR(bh))) {
                                ea_bdebug(bh, "b_count=%d",
                                          atomic_read(&(bh->b_count)));
-                               mb_cache_entry_release(ce);
+                               mb2_cache_entry_touch(ext2_mb_cache, ce);
+                               mb2_cache_entry_put(ext2_mb_cache, ce);
                                return bh;
                        }
                        unlock_buffer(bh);
                        brelse(bh);
                }
-               ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
+               ce = mb2_cache_entry_find_next(ext2_mb_cache, ce);
        }
        return NULL;
 }
@@ -1012,17 +1005,15 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *header,
 
 #undef BLOCK_HASH_SHIFT
 
-int __init
-init_ext2_xattr(void)
+#define HASH_BUCKET_BITS 10
+
+struct mb2_cache *ext2_xattr_create_cache(void)
 {
-       ext2_xattr_cache = mb_cache_create("ext2_xattr", 6);
-       if (!ext2_xattr_cache)
-               return -ENOMEM;
-       return 0;
+       return mb2_cache_create(HASH_BUCKET_BITS);
 }
 
-void
-exit_ext2_xattr(void)
+void ext2_xattr_destroy_cache(struct mb2_cache *cache)
 {
-       mb_cache_destroy(ext2_xattr_cache);
+       if (cache)
+               mb2_cache_destroy(cache);
 }
index 60edf29..6ea38aa 100644 (file)
@@ -53,6 +53,8 @@ struct ext2_xattr_entry {
 #define EXT2_XATTR_SIZE(size) \
        (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
 
+struct mb2_cache;
+
 # ifdef CONFIG_EXT2_FS_XATTR
 
 extern const struct xattr_handler ext2_xattr_user_handler;
@@ -65,10 +67,9 @@ extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t);
 extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
 
 extern void ext2_xattr_delete_inode(struct inode *);
-extern void ext2_xattr_put_super(struct super_block *);
 
-extern int init_ext2_xattr(void);
-extern void exit_ext2_xattr(void);
+extern struct mb2_cache *ext2_xattr_create_cache(void);
+extern void ext2_xattr_destroy_cache(struct mb2_cache *cache);
 
 extern const struct xattr_handler *ext2_xattr_handlers[];
 
@@ -93,19 +94,7 @@ ext2_xattr_delete_inode(struct inode *inode)
 {
 }
 
-static inline void
-ext2_xattr_put_super(struct super_block *sb)
-{
-}
-
-static inline int
-init_ext2_xattr(void)
-{
-       return 0;
-}
-
-static inline void
-exit_ext2_xattr(void)
+static inline void ext2_xattr_destroy_cache(struct mb2_cache *cache)
 {
 }
 
index 482d1ca..6c910f1 100644 (file)
@@ -1443,7 +1443,7 @@ struct ext4_sb_info {
        struct list_head s_es_list;     /* List of inodes with reclaimable extents */
        long s_es_nr_inode;
        struct ext4_es_stats s_es_stats;
-       struct mb_cache *s_mb_cache;
+       struct mb2_cache *s_mb_cache;
        spinlock_t s_es_lock ____cacheline_aligned_in_smp;
 
        /* Ratelimit ext4 messages. */
index 72b3849..4caa0c1 100644 (file)
@@ -73,10 +73,9 @@ static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
                        csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
                                           csum_size);
                        offset += csum_size;
-                       csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
-                                          EXT4_INODE_SIZE(inode->i_sb) -
-                                          offset);
                }
+               csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+                                  EXT4_INODE_SIZE(inode->i_sb) - offset);
        }
 
        return csum;
index 68345a9..bd8831b 100644 (file)
@@ -816,7 +816,6 @@ static void ext4_put_super(struct super_block *sb)
        ext4_release_system_zone(sb);
        ext4_mb_release(sb);
        ext4_ext_release(sb);
-       ext4_xattr_put_super(sb);
 
        if (!(sb->s_flags & MS_RDONLY) && !aborted) {
                ext4_clear_feature_journal_needs_recovery(sb);
@@ -3833,7 +3832,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
 no_journal:
        if (ext4_mballoc_ready) {
-               sbi->s_mb_cache = ext4_xattr_create_cache(sb->s_id);
+               sbi->s_mb_cache = ext4_xattr_create_cache();
                if (!sbi->s_mb_cache) {
                        ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
                        goto failed_mount_wq;
@@ -4065,6 +4064,10 @@ failed_mount4:
        if (EXT4_SB(sb)->rsv_conversion_wq)
                destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
 failed_mount_wq:
+       if (sbi->s_mb_cache) {
+               ext4_xattr_destroy_cache(sbi->s_mb_cache);
+               sbi->s_mb_cache = NULL;
+       }
        if (sbi->s_journal) {
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
index 7c23363..b310ed8 100644 (file)
@@ -53,7 +53,7 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/mbcache.h>
+#include <linux/mbcache2.h>
 #include <linux/quotaops.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
 # define ea_bdebug(bh, fmt, ...)       no_printk(fmt, ##__VA_ARGS__)
 #endif
 
-static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
+static void ext4_xattr_cache_insert(struct mb2_cache *, struct buffer_head *);
 static struct buffer_head *ext4_xattr_cache_find(struct inode *,
                                                 struct ext4_xattr_header *,
-                                                struct mb_cache_entry **);
+                                                struct mb2_cache_entry **);
 static void ext4_xattr_rehash(struct ext4_xattr_header *,
                              struct ext4_xattr_entry *);
 static int ext4_xattr_list(struct dentry *dentry, char *buffer,
@@ -300,7 +300,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
        struct ext4_xattr_entry *entry;
        size_t size;
        int error;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+       struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
        ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
                  name_index, name, buffer, (long)buffer_size);
@@ -447,7 +447,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
        struct inode *inode = d_inode(dentry);
        struct buffer_head *bh = NULL;
        int error;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+       struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
        ea_idebug(inode, "buffer=%p, buffer_size=%ld",
                  buffer, (long)buffer_size);
@@ -564,11 +564,8 @@ static void
 ext4_xattr_release_block(handle_t *handle, struct inode *inode,
                         struct buffer_head *bh)
 {
-       struct mb_cache_entry *ce = NULL;
        int error = 0;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
-       ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
        BUFFER_TRACE(bh, "get_write_access");
        error = ext4_journal_get_write_access(handle, bh);
        if (error)
@@ -576,9 +573,15 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
 
        lock_buffer(bh);
        if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
+               __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
+
                ea_bdebug(bh, "refcount now=0; freeing");
-               if (ce)
-                       mb_cache_entry_free(ce);
+               /*
+                * This must happen under buffer lock for
+                * ext4_xattr_block_set() to reliably detect freed block
+                */
+               mb2_cache_entry_delete_block(EXT4_GET_MB_CACHE(inode), hash,
+                                            bh->b_blocknr);
                get_bh(bh);
                unlock_buffer(bh);
                ext4_free_blocks(handle, inode, bh, 0, 1,
@@ -586,8 +589,6 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
                                 EXT4_FREE_BLOCKS_FORGET);
        } else {
                le32_add_cpu(&BHDR(bh)->h_refcount, -1);
-               if (ce)
-                       mb_cache_entry_release(ce);
                /*
                 * Beware of this ugliness: Releasing of xattr block references
                 * from different inodes can race and so we have to protect
@@ -800,17 +801,15 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
        struct super_block *sb = inode->i_sb;
        struct buffer_head *new_bh = NULL;
        struct ext4_xattr_search *s = &bs->s;
-       struct mb_cache_entry *ce = NULL;
+       struct mb2_cache_entry *ce = NULL;
        int error = 0;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+       struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
 #define header(x) ((struct ext4_xattr_header *)(x))
 
        if (i->value && i->value_len > sb->s_blocksize)
                return -ENOSPC;
        if (s->base) {
-               ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
-                                       bs->bh->b_blocknr);
                BUFFER_TRACE(bs->bh, "get_write_access");
                error = ext4_journal_get_write_access(handle, bs->bh);
                if (error)
@@ -818,10 +817,15 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                lock_buffer(bs->bh);
 
                if (header(s->base)->h_refcount == cpu_to_le32(1)) {
-                       if (ce) {
-                               mb_cache_entry_free(ce);
-                               ce = NULL;
-                       }
+                       __u32 hash = le32_to_cpu(BHDR(bs->bh)->h_hash);
+
+                       /*
+                        * This must happen under buffer lock for
+                        * ext4_xattr_block_set() to reliably detect modified
+                        * block
+                        */
+                       mb2_cache_entry_delete_block(ext4_mb_cache, hash,
+                                                    bs->bh->b_blocknr);
                        ea_bdebug(bs->bh, "modifying in-place");
                        error = ext4_xattr_set_entry(i, s);
                        if (!error) {
@@ -845,10 +849,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                        int offset = (char *)s->here - bs->bh->b_data;
 
                        unlock_buffer(bs->bh);
-                       if (ce) {
-                               mb_cache_entry_release(ce);
-                               ce = NULL;
-                       }
                        ea_bdebug(bs->bh, "cloning");
                        s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
                        error = -ENOMEM;
@@ -903,6 +903,31 @@ inserted:
                                if (error)
                                        goto cleanup_dquot;
                                lock_buffer(new_bh);
+                               /*
+                                * We have to be careful about races with
+                                * freeing or rehashing of xattr block. Once we
+                                * hold buffer lock xattr block's state is
+                                * stable so we can check whether the block got
+                                * freed / rehashed or not.  Since we unhash
+                                * mbcache entry under buffer lock when freeing
+                                * / rehashing xattr block, checking whether
+                                * entry is still hashed is reliable.
+                                */
+                               if (hlist_bl_unhashed(&ce->e_hash_list)) {
+                                       /*
+                                        * Undo everything and check mbcache
+                                        * again.
+                                        */
+                                       unlock_buffer(new_bh);
+                                       dquot_free_block(inode,
+                                                        EXT4_C2B(EXT4_SB(sb),
+                                                                 1));
+                                       brelse(new_bh);
+                                       mb2_cache_entry_put(ext4_mb_cache, ce);
+                                       ce = NULL;
+                                       new_bh = NULL;
+                                       goto inserted;
+                               }
                                le32_add_cpu(&BHDR(new_bh)->h_refcount, 1);
                                ea_bdebug(new_bh, "reusing; refcount now=%d",
                                        le32_to_cpu(BHDR(new_bh)->h_refcount));
@@ -913,7 +938,8 @@ inserted:
                                if (error)
                                        goto cleanup_dquot;
                        }
-                       mb_cache_entry_release(ce);
+                       mb2_cache_entry_touch(ext4_mb_cache, ce);
+                       mb2_cache_entry_put(ext4_mb_cache, ce);
                        ce = NULL;
                } else if (bs->bh && s->base == bs->bh->b_data) {
                        /* We were modifying this block in-place. */
@@ -978,7 +1004,7 @@ getblk_failed:
 
 cleanup:
        if (ce)
-               mb_cache_entry_release(ce);
+               mb2_cache_entry_put(ext4_mb_cache, ce);
        brelse(new_bh);
        if (!(bs->bh && s->base == bs->bh->b_data))
                kfree(s->base);
@@ -1543,17 +1569,6 @@ cleanup:
 }
 
 /*
- * ext4_xattr_put_super()
- *
- * This is called when a file system is unmounted.
- */
-void
-ext4_xattr_put_super(struct super_block *sb)
-{
-       mb_cache_shrink(sb->s_bdev);
-}
-
-/*
  * ext4_xattr_cache_insert()
  *
  * Create a new entry in the extended attribute cache, and insert
@@ -1562,28 +1577,18 @@ ext4_xattr_put_super(struct super_block *sb)
  * Returns 0, or a negative error number on failure.
  */
 static void
-ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh)
+ext4_xattr_cache_insert(struct mb2_cache *ext4_mb_cache, struct buffer_head *bh)
 {
        __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
-       struct mb_cache_entry *ce;
        int error;
 
-       ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
-       if (!ce) {
-               ea_bdebug(bh, "out of memory");
-               return;
-       }
-       error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
+       error = mb2_cache_entry_create(ext4_mb_cache, GFP_NOFS, hash,
+                                      bh->b_blocknr);
        if (error) {
-               mb_cache_entry_free(ce);
-               if (error == -EBUSY) {
+               if (error == -EBUSY)
                        ea_bdebug(bh, "already in cache");
-                       error = 0;
-               }
-       } else {
+       } else
                ea_bdebug(bh, "inserting [%x]", (int)hash);
-               mb_cache_entry_release(ce);
-       }
 }
 
 /*
@@ -1636,26 +1641,19 @@ ext4_xattr_cmp(struct ext4_xattr_header *header1,
  */
 static struct buffer_head *
 ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
-                     struct mb_cache_entry **pce)
+                     struct mb2_cache_entry **pce)
 {
        __u32 hash = le32_to_cpu(header->h_hash);
-       struct mb_cache_entry *ce;
-       struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
+       struct mb2_cache_entry *ce;
+       struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
 
        if (!header->h_hash)
                return NULL;  /* never share */
        ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
-again:
-       ce = mb_cache_entry_find_first(ext4_mb_cache, inode->i_sb->s_bdev,
-                                      hash);
+       ce = mb2_cache_entry_find_first(ext4_mb_cache, hash);
        while (ce) {
                struct buffer_head *bh;
 
-               if (IS_ERR(ce)) {
-                       if (PTR_ERR(ce) == -EAGAIN)
-                               goto again;
-                       break;
-               }
                bh = sb_bread(inode->i_sb, ce->e_block);
                if (!bh) {
                        EXT4_ERROR_INODE(inode, "block %lu read error",
@@ -1671,7 +1669,7 @@ again:
                        return bh;
                }
                brelse(bh);
-               ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
+               ce = mb2_cache_entry_find_next(ext4_mb_cache, ce);
        }
        return NULL;
 }
@@ -1746,15 +1744,15 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header,
 
 #define        HASH_BUCKET_BITS        10
 
-struct mb_cache *
-ext4_xattr_create_cache(char *name)
+struct mb2_cache *
+ext4_xattr_create_cache(void)
 {
-       return mb_cache_create(name, HASH_BUCKET_BITS);
+       return mb2_cache_create(HASH_BUCKET_BITS);
 }
 
-void ext4_xattr_destroy_cache(struct mb_cache *cache)
+void ext4_xattr_destroy_cache(struct mb2_cache *cache)
 {
        if (cache)
-               mb_cache_destroy(cache);
+               mb2_cache_destroy(cache);
 }
 
index ddc0957..10b0f73 100644 (file)
@@ -108,7 +108,6 @@ extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_
 extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
 
 extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
-extern void ext4_xattr_put_super(struct super_block *);
 
 extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
                            struct ext4_inode *raw_inode, handle_t *handle);
@@ -124,8 +123,8 @@ extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
                                       struct ext4_xattr_info *i,
                                       struct ext4_xattr_ibody_find *is);
 
-extern struct mb_cache *ext4_xattr_create_cache(char *name);
-extern void ext4_xattr_destroy_cache(struct mb_cache *);
+extern struct mb2_cache *ext4_xattr_create_cache(void);
+extern void ext4_xattr_destroy_cache(struct mb2_cache *);
 
 #ifdef CONFIG_EXT4_FS_SECURITY
 extern int ext4_init_security(handle_t *handle, struct inode *inode,
index 106dda1..92ac61c 100644 (file)
@@ -947,6 +947,14 @@ static int sanity_check_raw_super(struct super_block *sb,
                return 1;
        }
 
+       /* check log blocks per segment */
+       if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
+               f2fs_msg(sb, KERN_INFO,
+                       "Invalid log blocks per segment (%u)\n",
+                       le32_to_cpu(raw_super->log_blocks_per_seg));
+               return 1;
+       }
+
        /* Currently, support 512/1024/2048/4096 bytes sector size */
        if (le32_to_cpu(raw_super->log_sectorsize) >
                                F2FS_MAX_LOG_SECTOR_SIZE ||
index ad8a5b7..a443c6e 100644 (file)
@@ -760,7 +760,7 @@ static int get_first_leaf(struct gfs2_inode *dip, u32 index,
        int error;
 
        error = get_leaf_nr(dip, index, &leaf_no);
-       if (!error)
+       if (!IS_ERR_VALUE(error))
                error = get_leaf(dip, leaf_no, bh_out);
 
        return error;
@@ -976,7 +976,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
 
        index = name->hash >> (32 - dip->i_depth);
        error = get_leaf_nr(dip, index, &leaf_no);
-       if (error)
+       if (IS_ERR_VALUE(error))
                return error;
 
        /*  Get the old leaf block  */
index 187477d..ab1da98 100644 (file)
@@ -262,7 +262,6 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
                list_del_init(&ce->e_lru_list);
                if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))
                        continue;
-               spin_unlock(&mb_cache_spinlock);
                /* Prevent any find or get operation on the entry */
                hlist_bl_lock(ce->e_block_hash_p);
                hlist_bl_lock(ce->e_index_hash_p);
@@ -271,10 +270,10 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
                        !list_empty(&ce->e_lru_list)) {
                        hlist_bl_unlock(ce->e_index_hash_p);
                        hlist_bl_unlock(ce->e_block_hash_p);
-                       spin_lock(&mb_cache_spinlock);
                        continue;
                }
                __mb_cache_entry_unhash_unlock(ce);
+               spin_unlock(&mb_cache_spinlock);
                list_add_tail(&ce->e_lru_list, &free_list);
                spin_lock(&mb_cache_spinlock);
        }
@@ -516,7 +515,6 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags)
                                if (ce->e_used || ce->e_queued ||
                                        atomic_read(&ce->e_refcnt))
                                        continue;
-                               spin_unlock(&mb_cache_spinlock);
                                /*
                                 * Prevent any find or get operation on the
                                 * entry.
@@ -530,13 +528,13 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags)
                                        hlist_bl_unlock(ce->e_index_hash_p);
                                        hlist_bl_unlock(ce->e_block_hash_p);
                                        l = &mb_cache_lru_list;
-                                       spin_lock(&mb_cache_spinlock);
                                        continue;
                                }
                                mb_assert(list_empty(&ce->e_lru_list));
                                mb_assert(!(ce->e_used || ce->e_queued ||
                                        atomic_read(&ce->e_refcnt)));
                                __mb_cache_entry_unhash_unlock(ce);
+                               spin_unlock(&mb_cache_spinlock);
                                goto found;
                        }
                }
@@ -670,6 +668,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev,
                           cache->c_bucket_bits);
        block_hash_p = &cache->c_block_hash[bucket];
        /* First serialize access to the block corresponding hash chain. */
+       spin_lock(&mb_cache_spinlock);
        hlist_bl_lock(block_hash_p);
        hlist_bl_for_each_entry(ce, l, block_hash_p, e_block_list) {
                mb_assert(ce->e_block_hash_p == block_hash_p);
@@ -678,9 +677,11 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev,
                         * Prevent a free from removing the entry.
                         */
                        atomic_inc(&ce->e_refcnt);
+                       if (!list_empty(&ce->e_lru_list))
+                               list_del_init(&ce->e_lru_list);
                        hlist_bl_unlock(block_hash_p);
+                       spin_unlock(&mb_cache_spinlock);
                        __spin_lock_mb_cache_entry(ce);
-                       atomic_dec(&ce->e_refcnt);
                        if (ce->e_used > 0) {
                                DEFINE_WAIT(wait);
                                while (ce->e_used > 0) {
@@ -695,13 +696,9 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev,
                                finish_wait(&mb_cache_queue, &wait);
                        }
                        ce->e_used += 1 + MB_CACHE_WRITER;
+                       atomic_dec(&ce->e_refcnt);
                        __spin_unlock_mb_cache_entry(ce);
 
-                       if (!list_empty(&ce->e_lru_list)) {
-                               spin_lock(&mb_cache_spinlock);
-                               list_del_init(&ce->e_lru_list);
-                               spin_unlock(&mb_cache_spinlock);
-                       }
                        if (!__mb_cache_entry_is_block_hashed(ce)) {
                                __mb_cache_entry_release(ce);
                                return NULL;
@@ -710,6 +707,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev,
                }
        }
        hlist_bl_unlock(block_hash_p);
+       spin_unlock(&mb_cache_spinlock);
        return NULL;
 }
 
diff --git a/fs/mbcache2.c b/fs/mbcache2.c
new file mode 100644 (file)
index 0000000..5c3e1a8
--- /dev/null
@@ -0,0 +1,359 @@
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/list_bl.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mbcache2.h>
+
+/*
+ * Mbcache is a simple key-value store. Keys need not be unique, however
+ * key-value pairs are expected to be unique (we use this fact in
+ * mb2_cache_entry_delete_block()).
+ *
+ * Ext2 and ext4 use this cache for deduplication of extended attribute blocks.
+ * They use hash of a block contents as a key and block number as a value.
+ * That's why keys need not be unique (different xattr blocks may end up having
+ * the same hash). However block number always uniquely identifies a cache
+ * entry.
+ *
+ * We provide functions for creation and removal of entries, search by key,
+ * and a special "delete entry with given key-value pair" operation. Fixed
+ * size hash table is used for fast key lookups.
+ */
+
+struct mb2_cache {
+       /* Hash table of entries */
+       struct hlist_bl_head    *c_hash;
+       /* log2 of hash table size */
+       int                     c_bucket_bits;
+       /* Protects c_lru_list, c_entry_count */
+       spinlock_t              c_lru_list_lock;
+       struct list_head        c_lru_list;
+       /* Number of entries in cache */
+       unsigned long           c_entry_count;
+       struct shrinker         c_shrink;
+};
+
+static struct kmem_cache *mb2_entry_cache;
+
+/*
+ * mb2_cache_entry_create - create entry in cache
+ * @cache - cache where the entry should be created
+ * @mask - gfp mask with which the entry should be allocated
+ * @key - key of the entry
+ * @block - block that contains data
+ *
+ * Creates entry in @cache with key @key and records that data is stored in
+ * block @block. The function returns -EBUSY if entry with the same key
+ * and for the same block already exists in cache. Otherwise 0 is returned.
+ */
+int mb2_cache_entry_create(struct mb2_cache *cache, gfp_t mask, u32 key,
+                          sector_t block)
+{
+       struct mb2_cache_entry *entry, *dup;
+       struct hlist_bl_node *dup_node;
+       struct hlist_bl_head *head;
+
+       entry = kmem_cache_alloc(mb2_entry_cache, mask);
+       if (!entry)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&entry->e_lru_list);
+       /* One ref for hash, one ref returned */
+       atomic_set(&entry->e_refcnt, 1);
+       entry->e_key = key;
+       entry->e_block = block;
+       head = &cache->c_hash[hash_32(key, cache->c_bucket_bits)];
+       entry->e_hash_list_head = head;
+       hlist_bl_lock(head);
+       hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
+               if (dup->e_key == key && dup->e_block == block) {
+                       hlist_bl_unlock(head);
+                       kmem_cache_free(mb2_entry_cache, entry);
+                       return -EBUSY;
+               }
+       }
+       hlist_bl_add_head(&entry->e_hash_list, head);
+       hlist_bl_unlock(head);
+
+       spin_lock(&cache->c_lru_list_lock);
+       list_add_tail(&entry->e_lru_list, &cache->c_lru_list);
+       /* Grab ref for LRU list */
+       atomic_inc(&entry->e_refcnt);
+       cache->c_entry_count++;
+       spin_unlock(&cache->c_lru_list_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(mb2_cache_entry_create);
+
+void __mb2_cache_entry_free(struct mb2_cache_entry *entry)
+{
+       kmem_cache_free(mb2_entry_cache, entry);
+}
+EXPORT_SYMBOL(__mb2_cache_entry_free);
+
+static struct mb2_cache_entry *__entry_find(struct mb2_cache *cache,
+                                           struct mb2_cache_entry *entry,
+                                           u32 key)
+{
+       struct mb2_cache_entry *old_entry = entry;
+       struct hlist_bl_node *node;
+       struct hlist_bl_head *head;
+
+       if (entry)
+               head = entry->e_hash_list_head;
+       else
+               head = &cache->c_hash[hash_32(key, cache->c_bucket_bits)];
+       hlist_bl_lock(head);
+       if (entry && !hlist_bl_unhashed(&entry->e_hash_list))
+               node = entry->e_hash_list.next;
+       else
+               node = hlist_bl_first(head);
+       while (node) {
+               entry = hlist_bl_entry(node, struct mb2_cache_entry,
+                                      e_hash_list);
+               if (entry->e_key == key) {
+                       atomic_inc(&entry->e_refcnt);
+                       goto out;
+               }
+               node = node->next;
+       }
+       entry = NULL;
+out:
+       hlist_bl_unlock(head);
+       if (old_entry)
+               mb2_cache_entry_put(cache, old_entry);
+
+       return entry;
+}
+
+/*
+ * mb2_cache_entry_find_first - find the first entry in cache with given key
+ * @cache: cache where we should search
+ * @key: key to look for
+ *
+ * Search in @cache for entry with key @key. Grabs reference to the first
+ * entry found and returns the entry.
+ */
+struct mb2_cache_entry *mb2_cache_entry_find_first(struct mb2_cache *cache,
+                                                  u32 key)
+{
+       return __entry_find(cache, NULL, key);
+}
+EXPORT_SYMBOL(mb2_cache_entry_find_first);
+
+/*
+ * mb2_cache_entry_find_next - find next entry in cache with the same
+ * @cache: cache where we should search
+ * @entry: entry to start search from
+ *
+ * Finds next entry in the hash chain which has the same key as @entry.
+ * If @entry is unhashed (which can happen when deletion of entry races
+ * with the search), finds the first entry in the hash chain. The function
+ * drops reference to @entry and returns with a reference to the found entry.
+ */
+struct mb2_cache_entry *mb2_cache_entry_find_next(struct mb2_cache *cache,
+                                                 struct mb2_cache_entry *entry)
+{
+       return __entry_find(cache, entry, entry->e_key);
+}
+EXPORT_SYMBOL(mb2_cache_entry_find_next);
+
+/* mb2_cache_entry_delete_block - remove information about block from cache
+ * @cache - cache we work with
+ * @key - key of the entry to remove
+ * @block - block containing data for @key
+ *
+ * Remove entry from cache @cache with key @key with data stored in @block.
+ */
+void mb2_cache_entry_delete_block(struct mb2_cache *cache, u32 key,
+                                 sector_t block)
+{
+       struct hlist_bl_node *node;
+       struct hlist_bl_head *head;
+       struct mb2_cache_entry *entry;
+
+       head = &cache->c_hash[hash_32(key, cache->c_bucket_bits)];
+       hlist_bl_lock(head);
+       hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
+               if (entry->e_key == key && entry->e_block == block) {
+                       /* We keep hash list reference to keep entry alive */
+                       hlist_bl_del_init(&entry->e_hash_list);
+                       hlist_bl_unlock(head);
+                       spin_lock(&cache->c_lru_list_lock);
+                       if (!list_empty(&entry->e_lru_list)) {
+                               list_del_init(&entry->e_lru_list);
+                               cache->c_entry_count--;
+                               atomic_dec(&entry->e_refcnt);
+                       }
+                       spin_unlock(&cache->c_lru_list_lock);
+                       mb2_cache_entry_put(cache, entry);
+                       return;
+               }
+       }
+       hlist_bl_unlock(head);
+}
+EXPORT_SYMBOL(mb2_cache_entry_delete_block);
+
+/* mb2_cache_entry_touch - cache entry got used
+ * @cache - cache the entry belongs to
+ * @entry - entry that got used
+ *
+ * Move entry in lru list to reflect the fact that it was used.
+ */
+void mb2_cache_entry_touch(struct mb2_cache *cache,
+                          struct mb2_cache_entry *entry)
+{
+       spin_lock(&cache->c_lru_list_lock);
+       if (!list_empty(&entry->e_lru_list))
+               list_move_tail(&cache->c_lru_list, &entry->e_lru_list);
+       spin_unlock(&cache->c_lru_list_lock);
+}
+EXPORT_SYMBOL(mb2_cache_entry_touch);
+
+static unsigned long mb2_cache_count(struct shrinker *shrink,
+                                    struct shrink_control *sc)
+{
+       struct mb2_cache *cache = container_of(shrink, struct mb2_cache,
+                                              c_shrink);
+
+       return cache->c_entry_count;
+}
+
+/* Shrink number of entries in cache */
+static unsigned long mb2_cache_scan(struct shrinker *shrink,
+                                   struct shrink_control *sc)
+{
+       int nr_to_scan = sc->nr_to_scan;
+       struct mb2_cache *cache = container_of(shrink, struct mb2_cache,
+                                             c_shrink);
+       struct mb2_cache_entry *entry;
+       struct hlist_bl_head *head;
+       unsigned int shrunk = 0;
+
+       spin_lock(&cache->c_lru_list_lock);
+       while (nr_to_scan-- && !list_empty(&cache->c_lru_list)) {
+               entry = list_first_entry(&cache->c_lru_list,
+                                        struct mb2_cache_entry, e_lru_list);
+               list_del_init(&entry->e_lru_list);
+               cache->c_entry_count--;
+               /*
+                * We keep LRU list reference so that entry doesn't go away
+                * from under us.
+                */
+               spin_unlock(&cache->c_lru_list_lock);
+               head = entry->e_hash_list_head;
+               hlist_bl_lock(head);
+               if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+                       hlist_bl_del_init(&entry->e_hash_list);
+                       atomic_dec(&entry->e_refcnt);
+               }
+               hlist_bl_unlock(head);
+               if (mb2_cache_entry_put(cache, entry))
+                       shrunk++;
+               cond_resched();
+               spin_lock(&cache->c_lru_list_lock);
+       }
+       spin_unlock(&cache->c_lru_list_lock);
+
+       return shrunk;
+}
+
+/*
+ * mb2_cache_create - create cache
+ * @bucket_bits: log2 of the hash table size
+ *
+ * Create cache for keys with 2^bucket_bits hash entries.
+ */
+struct mb2_cache *mb2_cache_create(int bucket_bits)
+{
+       struct mb2_cache *cache;
+       int bucket_count = 1 << bucket_bits;
+       int i;
+
+       if (!try_module_get(THIS_MODULE))
+               return NULL;
+
+       cache = kzalloc(sizeof(struct mb2_cache), GFP_KERNEL);
+       if (!cache)
+               goto err_out;
+       cache->c_bucket_bits = bucket_bits;
+       INIT_LIST_HEAD(&cache->c_lru_list);
+       spin_lock_init(&cache->c_lru_list_lock);
+       cache->c_hash = kmalloc(bucket_count * sizeof(struct hlist_bl_head),
+                               GFP_KERNEL);
+       if (!cache->c_hash) {
+               kfree(cache);
+               goto err_out;
+       }
+       for (i = 0; i < bucket_count; i++)
+               INIT_HLIST_BL_HEAD(&cache->c_hash[i]);
+
+       cache->c_shrink.count_objects = mb2_cache_count;
+       cache->c_shrink.scan_objects = mb2_cache_scan;
+       cache->c_shrink.seeks = DEFAULT_SEEKS;
+       register_shrinker(&cache->c_shrink);
+
+       return cache;
+
+err_out:
+       module_put(THIS_MODULE);
+       return NULL;
+}
+EXPORT_SYMBOL(mb2_cache_create);
+
+/*
+ * mb2_cache_destroy - destroy cache
+ * @cache: the cache to destroy
+ *
+ * Free all entries in cache and cache itself. Caller must make sure nobody
+ * (except shrinker) can reach @cache when calling this.
+ */
+void mb2_cache_destroy(struct mb2_cache *cache)
+{
+       struct mb2_cache_entry *entry, *next;
+
+       unregister_shrinker(&cache->c_shrink);
+
+       /*
+        * We don't bother with any locking. Cache must not be used at this
+        * point.
+        */
+       list_for_each_entry_safe(entry, next, &cache->c_lru_list, e_lru_list) {
+               if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+                       hlist_bl_del_init(&entry->e_hash_list);
+                       atomic_dec(&entry->e_refcnt);
+               } else
+                       WARN_ON(1);
+               list_del(&entry->e_lru_list);
+               WARN_ON(atomic_read(&entry->e_refcnt) != 1);
+               mb2_cache_entry_put(cache, entry);
+       }
+       kfree(cache->c_hash);
+       kfree(cache);
+       module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL(mb2_cache_destroy);
+
+static int __init mb2cache_init(void)
+{
+       mb2_entry_cache = kmem_cache_create("mbcache",
+                               sizeof(struct mb2_cache_entry), 0,
+                               SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
+       BUG_ON(!mb2_entry_cache);
+       return 0;
+}
+
+static void __exit mb2cache_exit(void)
+{
+       kmem_cache_destroy(mb2_entry_cache);
+}
+
+module_init(mb2cache_init)
+module_exit(mb2cache_exit)
+
+MODULE_AUTHOR("Jan Kara <jack@suse.cz>");
+MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
+MODULE_LICENSE("GPL");
index 3dc7dea..13a4ebb 100644 (file)
@@ -13,6 +13,8 @@ struct mnt_namespace {
        u64                     seq;    /* Sequence number to prevent loops */
        wait_queue_head_t poll;
        u64 event;
+       unsigned int            mounts; /* # of mounts in the namespace */
+       unsigned int            pending_mounts;
 };
 
 struct mnt_pcp {
index c147788..a22959c 100644 (file)
@@ -27,6 +27,9 @@
 #include "pnode.h"
 #include "internal.h"
 
+/* Maximum number of mounts in a mount namespace */
+unsigned int sysctl_mount_max __read_mostly = 100000;
+
 static unsigned int m_hash_mask __read_mostly;
 static unsigned int m_hash_shift __read_mostly;
 static unsigned int mp_hash_mask __read_mostly;
@@ -926,6 +929,9 @@ static void commit_tree(struct mount *mnt)
 
        list_splice(&head, n->list.prev);
 
+       n->mounts += n->pending_mounts;
+       n->pending_mounts = 0;
+
        __attach_mnt(mnt, parent);
        touch_mnt_namespace(n);
 }
@@ -1465,11 +1471,16 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
                propagate_umount(&tmp_list);
 
        while (!list_empty(&tmp_list)) {
+               struct mnt_namespace *ns;
                bool disconnect;
                p = list_first_entry(&tmp_list, struct mount, mnt_list);
                list_del_init(&p->mnt_expire);
                list_del_init(&p->mnt_list);
-               __touch_mnt_namespace(p->mnt_ns);
+               ns = p->mnt_ns;
+               if (ns) {
+                       ns->mounts--;
+                       __touch_mnt_namespace(ns);
+               }
                p->mnt_ns = NULL;
                if (how & UMOUNT_SYNC)
                        p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
@@ -1870,6 +1881,28 @@ static int invent_group_ids(struct mount *mnt, bool recurse)
        return 0;
 }
 
+int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
+{
+       unsigned int max = READ_ONCE(sysctl_mount_max);
+       unsigned int mounts = 0, old, pending, sum;
+       struct mount *p;
+
+       for (p = mnt; p; p = next_mnt(p, mnt))
+               mounts++;
+
+       old = ns->mounts;
+       pending = ns->pending_mounts;
+       sum = old + pending;
+       if ((old > sum) ||
+           (pending > sum) ||
+           (max < sum) ||
+           (mounts > (max - sum)))
+               return -ENOSPC;
+
+       ns->pending_mounts = pending + mounts;
+       return 0;
+}
+
 /*
  *  @source_mnt : mount tree to be attached
  *  @nd         : place the mount tree @source_mnt is attached
@@ -1939,6 +1972,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
                        struct path *parent_path)
 {
        HLIST_HEAD(tree_list);
+       struct mnt_namespace *ns = dest_mnt->mnt_ns;
        struct mountpoint *smp;
        struct mount *child, *p;
        struct hlist_node *n;
@@ -1951,6 +1985,13 @@ static int attach_recursive_mnt(struct mount *source_mnt,
        if (IS_ERR(smp))
                return PTR_ERR(smp);
 
+       /* Is there space to add these mounts to the mount namespace? */
+       if (!parent_path) {
+               err = count_mounts(ns, source_mnt);
+               if (err)
+                       goto out;
+       }
+
        if (IS_MNT_SHARED(dest_mnt)) {
                err = invent_group_ids(source_mnt, true);
                if (err)
@@ -1990,11 +2031,14 @@ static int attach_recursive_mnt(struct mount *source_mnt,
  out_cleanup_ids:
        while (!hlist_empty(&tree_list)) {
                child = hlist_entry(tree_list.first, struct mount, mnt_hash);
+               child->mnt_parent->mnt_ns->pending_mounts = 0;
                umount_tree(child, UMOUNT_SYNC);
        }
        unlock_mount_hash();
        cleanup_group_ids(source_mnt, NULL);
  out:
+       ns->pending_mounts = 0;
+
        read_seqlock_excl(&mount_lock);
        put_mountpoint(smp);
        read_sequnlock_excl(&mount_lock);
@@ -2830,6 +2874,8 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
        init_waitqueue_head(&new_ns->poll);
        new_ns->event = 0;
        new_ns->user_ns = get_user_ns(user_ns);
+       new_ns->mounts = 0;
+       new_ns->pending_mounts = 0;
        return new_ns;
 }
 
@@ -2879,6 +2925,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
        q = new;
        while (p) {
                q->mnt_ns = new_ns;
+               new_ns->mounts++;
                if (new_fs) {
                        if (&p->mnt == new_fs->root.mnt) {
                                new_fs->root.mnt = mntget(&q->mnt);
@@ -2917,6 +2964,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
                struct mount *mnt = real_mount(m);
                mnt->mnt_ns = new_ns;
                new_ns->root = mnt;
+               new_ns->mounts++;
                list_add(&mnt->mnt_list, &new_ns->list);
        } else {
                mntput(m);
index 1d16bb3..b5f97c6 100644 (file)
@@ -259,7 +259,7 @@ static int propagate_one(struct mount *m)
                read_sequnlock_excl(&mount_lock);
        }
        hlist_add_head(&child->mnt_hash, list);
-       return 0;
+       return count_mounts(m->mnt_ns, child);
 }
 
 /*
index f41fc9a..a9a6576 100644 (file)
@@ -55,4 +55,5 @@ void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp,
 struct mount *copy_tree(struct mount *, struct dentry *, int);
 bool is_path_reachable(struct mount *, struct dentry *,
                         const struct path *root);
+int count_mounts(struct mnt_namespace *ns, struct mount *mnt);
 #endif /* _LINUX_PNODE_H */
index 6a44fb9..fc5243c 100644 (file)
@@ -867,7 +867,14 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma,
 static inline void clear_soft_dirty_pmd(struct vm_area_struct *vma,
                unsigned long addr, pmd_t *pmdp)
 {
-       pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp);
+       pmd_t pmd = *pmdp;
+
+       /* See comment in change_huge_pmd() */
+       pmdp_invalidate(vma, addr, pmdp);
+       if (pmd_dirty(*pmdp))
+               pmd = pmd_mkdirty(pmd);
+       if (pmd_young(*pmdp))
+               pmd = pmd_mkyoung(pmd);
 
        pmd = pmd_wrprotect(pmd);
        pmd = pmd_clear_soft_dirty(pmd);
index 8e31d1a..7a19e77 100644 (file)
@@ -60,6 +60,14 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags)
        lower_dentry = lower_path.dentry;
        lower_cur_parent_dentry = dget_parent(lower_dentry);
 
+       if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+               err = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
+               if (err == 0) {
+                       d_drop(dentry);
+                       goto out;
+               }
+       }
+
        spin_lock(&lower_dentry->d_lock);
        if (d_unhashed(lower_dentry)) {
                spin_unlock(&lower_dentry->d_lock);
index f82fedd..b4595aa 100644 (file)
@@ -215,16 +215,16 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name)
                gid = AID_MEDIA_OBB;
                break;
        case PERM_ANDROID_PACKAGE:
-               if (info->d_uid != 0)
+               if (uid_is_app(info->d_uid))
                        gid = multiuser_get_ext_gid(info->d_uid);
                else
-                       gid = multiuser_get_uid(info->userid, uid);
+                       gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
                break;
        case PERM_ANDROID_PACKAGE_CACHE:
-               if (info->d_uid != 0)
-                       gid = multiuser_get_cache_gid(info->d_uid);
+               if (uid_is_app(info->d_uid))
+                       gid = multiuser_get_ext_cache_gid(info->d_uid);
                else
-                       gid = multiuser_get_uid(info->userid, uid);
+                       gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
                break;
        case PERM_PRE_ROOT:
        default:
@@ -252,7 +252,7 @@ retry_deleg:
                                goto retry_deleg;
                }
                if (error)
-                       pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n");
+                       pr_debug("sdcardfs: Failed to touch up lower fs gid/uid for %s\n", name);
        }
        sdcardfs_put_lower_path(dentry, &path);
 }
index c0146e0..6076c34 100644 (file)
@@ -192,6 +192,9 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma)
        file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */
        if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */
                SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops;
+       vma->vm_private_data = file;
+       get_file(lower_file);
+       vma->vm_file = lower_file;
 
 out:
        return err;
@@ -355,9 +358,12 @@ ssize_t sdcardfs_read_iter(struct kiocb *iocb, struct iov_iter *iter)
        get_file(lower_file); /* prevent lower_file from being released */
        iocb->ki_filp = lower_file;
        err = lower_file->f_op->read_iter(iocb, iter);
-       /* ? wait IO finish to update atime as ecryptfs ? */
        iocb->ki_filp = file;
        fput(lower_file);
+       /* update upper inode atime as needed */
+       if (err >= 0 || err == -EIOCBQUEUED)
+               fsstack_copy_attr_atime(file->f_path.dentry->d_inode,
+                                       file_inode(lower_file));
 out:
        return err;
 }
@@ -381,6 +387,13 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
        err = lower_file->f_op->write_iter(iocb, iter);
        iocb->ki_filp = file;
        fput(lower_file);
+       /* update upper inode times/sizes as needed */
+       if (err >= 0 || err == -EIOCBQUEUED) {
+               fsstack_copy_inode_size(file->f_path.dentry->d_inode,
+                                       file_inode(lower_file));
+               fsstack_copy_attr_times(file->f_path.dentry->d_inode,
+                                       file_inode(lower_file));
+       }
 out:
        return err;
 }
index f10f775..509d5fb 100644 (file)
@@ -91,7 +91,9 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u
        struct sdcardfs_inode_info *info;
        struct inode_data data;
        struct inode *inode; /* the new inode to return */
-       int err;
+
+       if (!igrab(lower_inode))
+               return ERR_PTR(-ESTALE);
 
        data.id = id;
        data.lower_inode = lower_inode;
@@ -106,22 +108,19 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u
                             sdcardfs_inode_set, /* inode init function */
                             &data); /* data passed to test+set fxns */
        if (!inode) {
-               err = -EACCES;
                iput(lower_inode);
-               return ERR_PTR(err);
+               return ERR_PTR(-ENOMEM);
        }
-       /* if found a cached inode, then just return it */
-       if (!(inode->i_state & I_NEW))
+       /* if found a cached inode, then just return it (after iput) */
+       if (!(inode->i_state & I_NEW)) {
+               iput(lower_inode);
                return inode;
+       }
 
        /* initialize new inode */
        info = SDCARDFS_I(inode);
 
        inode->i_ino = lower_inode->i_ino;
-       if (!igrab(lower_inode)) {
-               err = -ESTALE;
-               return ERR_PTR(err);
-       }
        sdcardfs_set_lower_inode(inode, lower_inode);
 
        inode->i_version++;
@@ -367,19 +366,22 @@ put_name:
        /* instatiate a new negative dentry */
        dname.name = name->name;
        dname.len = name->len;
-       dname.hash = full_name_hash(dname.name, dname.len);
-       lower_dentry = d_lookup(lower_dir_dentry, &dname);
-       if (lower_dentry)
-               goto setup_lower;
 
-       lower_dentry = d_alloc(lower_dir_dentry, &dname);
+       /* See if the low-level filesystem might want
+        * to use its own hash
+        */
+       lower_dentry = d_hash_and_lookup(lower_dir_dentry, &dname);
+       if (IS_ERR(lower_dentry))
+               return lower_dentry;
        if (!lower_dentry) {
-               err = -ENOMEM;
+               /* We called vfs_path_lookup earlier, and did not get a negative
+                * dentry then. Don't confuse the lower filesystem by forcing
+                * one on it now...
+                */
+               err = -ENOENT;
                goto out;
        }
-       d_add(lower_dentry, NULL); /* instantiate and hash */
 
-setup_lower:
        lower_path.dentry = lower_dentry;
        lower_path.mnt = mntget(lower_dir_mnt);
        sdcardfs_set_lower_path(dentry, &lower_path);
index 0d4089c..b61f822 100644 (file)
 static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        int err;
-       struct file *file, *lower_file;
+       struct file *file;
        const struct vm_operations_struct *lower_vm_ops;
-       struct vm_area_struct lower_vma;
 
-       memcpy(&lower_vma, vma, sizeof(struct vm_area_struct));
-       file = lower_vma.vm_file;
+       file = (struct file *)vma->vm_private_data;
        lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops;
        BUG_ON(!lower_vm_ops);
 
-       lower_file = sdcardfs_lower_file(file);
-       /*
-        * XXX: vm_ops->fault may be called in parallel.  Because we have to
-        * resort to temporarily changing the vma->vm_file to point to the
-        * lower file, a concurrent invocation of sdcardfs_fault could see a
-        * different value.  In this workaround, we keep a different copy of
-        * the vma structure in our stack, so we never expose a different
-        * value of the vma->vm_file called to us, even temporarily.  A
-        * better fix would be to change the calling semantics of ->fault to
-        * take an explicit file pointer.
-        */
-       lower_vma.vm_file = lower_file;
-       err = lower_vm_ops->fault(&lower_vma, vmf);
+       err = lower_vm_ops->fault(vma, vmf);
        return err;
 }
 
+static void sdcardfs_vm_open(struct vm_area_struct *vma)
+{
+       struct file *file = (struct file *)vma->vm_private_data;
+
+       get_file(file);
+}
+
+static void sdcardfs_vm_close(struct vm_area_struct *vma)
+{
+       struct file *file = (struct file *)vma->vm_private_data;
+
+       fput(file);
+}
+
 static int sdcardfs_page_mkwrite(struct vm_area_struct *vma,
                               struct vm_fault *vmf)
 {
        int err = 0;
-       struct file *file, *lower_file;
+       struct file *file;
        const struct vm_operations_struct *lower_vm_ops;
-       struct vm_area_struct lower_vma;
 
-       memcpy(&lower_vma, vma, sizeof(struct vm_area_struct));
-       file = lower_vma.vm_file;
+       file = (struct file *)vma->vm_private_data;
        lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops;
        BUG_ON(!lower_vm_ops);
        if (!lower_vm_ops->page_mkwrite)
                goto out;
 
-       lower_file = sdcardfs_lower_file(file);
-       /*
-        * XXX: vm_ops->page_mkwrite may be called in parallel.
-        * Because we have to resort to temporarily changing the
-        * vma->vm_file to point to the lower file, a concurrent
-        * invocation of sdcardfs_page_mkwrite could see a different
-        * value.  In this workaround, we keep a different copy of the
-        * vma structure in our stack, so we never expose a different
-        * value of the vma->vm_file called to us, even temporarily.
-        * A better fix would be to change the calling semantics of
-        * ->page_mkwrite to take an explicit file pointer.
-        */
-       lower_vma.vm_file = lower_file;
-       err = lower_vm_ops->page_mkwrite(&lower_vma, vmf);
+       err = lower_vm_ops->page_mkwrite(vma, vmf);
 out:
        return err;
 }
@@ -99,4 +84,6 @@ const struct address_space_operations sdcardfs_aops = {
 const struct vm_operations_struct sdcardfs_vm_ops = {
        .fault          = sdcardfs_fault,
        .page_mkwrite   = sdcardfs_page_mkwrite,
+       .open           = sdcardfs_vm_open,
+       .close          = sdcardfs_vm_close,
 };
index 2e89b58..85341e7 100644 (file)
@@ -23,6 +23,8 @@
 #define AID_APP_END          19999 /* last app user */
 #define AID_CACHE_GID_START  20000 /* start of gids for apps to mark cached data */
 #define AID_EXT_GID_START    30000 /* start of gids for apps to mark external data */
+#define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */
+#define AID_EXT_CACHE_GID_END 49999   /* end of gids for apps to mark external cached data */
 #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
 
 typedef uid_t userid_t;
@@ -33,9 +35,16 @@ static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id)
        return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
 }
 
-static inline gid_t multiuser_get_cache_gid(uid_t uid)
+static inline bool uid_is_app(uid_t uid)
 {
-       return uid - AID_APP_START + AID_CACHE_GID_START;
+       appid_t appid = uid % AID_USER_OFFSET;
+
+       return appid >= AID_APP_START && appid <= AID_APP_END;
+}
+
+static inline gid_t multiuser_get_ext_cache_gid(uid_t uid)
+{
+       return uid - AID_APP_START + AID_EXT_CACHE_GID_START;
 }
 
 static inline gid_t multiuser_get_ext_gid(uid_t uid)
index b803213..39c75a8 100644 (file)
@@ -108,7 +108,7 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
 {
        const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
        struct kobject *kobj = of->kn->parent->priv;
-       size_t len;
+       ssize_t len;
 
        /*
         * If buf != of->prealloc_buf, we don't know how
@@ -117,13 +117,15 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
        if (WARN_ON_ONCE(buf != of->prealloc_buf))
                return 0;
        len = ops->show(kobj, of->kn->priv, buf);
+       if (len < 0)
+               return len;
        if (pos) {
                if (len <= pos)
                        return 0;
                len -= pos;
                memmove(buf, buf + pos, len);
        }
-       return min(count, len);
+       return min_t(ssize_t, count, len);
 }
 
 /* kernfs write callback for regular sysfs files */
index 476d99d..611b3d3 100644 (file)
@@ -181,6 +181,16 @@ static inline struct ahash_instance *ahash_alloc_instance(
        return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
 }
 
+static inline void ahash_request_complete(struct ahash_request *req, int err)
+{
+       req->base.complete(&req->base, err);
+}
+
+static inline u32 ahash_request_flags(struct ahash_request *req)
+{
+       return req->base.flags;
+}
+
 static inline struct crypto_ahash *crypto_spawn_ahash(
        struct crypto_ahash_spawn *spawn)
 {
index ed953f9..1487011 100644 (file)
@@ -229,6 +229,8 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
  * @ref_type: The type of reference.
  * @existed: Upon completion, indicates that an identical reference object
  * already existed, and the refcount was upped on that object instead.
+ * @require_existed: Fail with -EPERM if an identical ref object didn't
+ * already exist.
  *
  * Checks that the base object is shareable and adds a ref object to it.
  *
@@ -243,7 +245,8 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
  */
 extern int ttm_ref_object_add(struct ttm_object_file *tfile,
                              struct ttm_base_object *base,
-                             enum ttm_ref_type ref_type, bool *existed);
+                             enum ttm_ref_type ref_type, bool *existed,
+                             bool require_existed);
 
 extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
                                  struct ttm_base_object *base);
index cb91b44..ad2bcf6 100644 (file)
@@ -528,6 +528,25 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp)
        pr_cont_kernfs_path(cgrp->kn);
 }
 
+static inline void cgroup_init_kthreadd(void)
+{
+       /*
+        * kthreadd is inherited by all kthreads, keep it in the root so
+        * that the new kthreads are guaranteed to stay in the root until
+        * initialization is finished.
+        */
+       current->no_cgroup_migration = 1;
+}
+
+static inline void cgroup_kthread_ready(void)
+{
+       /*
+        * This kthread finished initialization.  The creator should have
+        * set PF_NO_SETAFFINITY if this kthread should stay in the root.
+        */
+       current->no_cgroup_migration = 0;
+}
+
 #else /* !CONFIG_CGROUPS */
 
 struct cgroup_subsys_state;
@@ -551,6 +570,8 @@ static inline void cgroup_free(struct task_struct *p) {}
 
 static inline int cgroup_init_early(void) { return 0; }
 static inline int cgroup_init(void) { return 0; }
+static inline void cgroup_init_kthreadd(void) {}
+static inline void cgroup_kthread_ready(void) {}
 
 #endif /* !CONFIG_CGROUPS */
 
index d8f4316..6cfef27 100644 (file)
@@ -1677,6 +1677,9 @@ enum ieee80211_statuscode {
        WLAN_STATUS_REJECT_DSE_BAND = 96,
        WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
        WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
+       /* 802.11ai */
+       WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108,
+       WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109,
 };
 
 
@@ -2035,6 +2038,15 @@ enum ieee80211_key_len {
 #define IEEE80211_GCMP_MIC_LEN         16
 #define IEEE80211_GCMP_PN_LEN          6
 
+#define FILS_NONCE_LEN                 16
+#define FILS_MAX_KEK_LEN               64
+
+#define FILS_ERP_MAX_USERNAME_LEN      16
+#define FILS_ERP_MAX_REALM_LEN         253
+#define FILS_ERP_MAX_RRK_LEN           64
+
+#define PMK_MAX_LEN                    48
+
 /* Public action codes */
 enum ieee80211_pub_actioncode {
        WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,
@@ -2248,31 +2260,37 @@ enum ieee80211_sa_query_action {
 };
 
 
+#define SUITE(oui, id) (((oui) << 8) | (id))
+
 /* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP    0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40                0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP         0x000FAC02
-/* reserved:                           0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP         0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104       0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC     0x000FAC06
-#define WLAN_CIPHER_SUITE_GCMP         0x000FAC08
-#define WLAN_CIPHER_SUITE_GCMP_256     0x000FAC09
-#define WLAN_CIPHER_SUITE_CCMP_256     0x000FAC0A
-#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B
-#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
-#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D
-
-#define WLAN_CIPHER_SUITE_SMS4         0x00147201
+#define WLAN_CIPHER_SUITE_USE_GROUP    SUITE(0x000FAC, 0)
+#define WLAN_CIPHER_SUITE_WEP40                SUITE(0x000FAC, 1)
+#define WLAN_CIPHER_SUITE_TKIP         SUITE(0x000FAC, 2)
+/* reserved:                           SUITE(0x000FAC, 3) */
+#define WLAN_CIPHER_SUITE_CCMP         SUITE(0x000FAC, 4)
+#define WLAN_CIPHER_SUITE_WEP104       SUITE(0x000FAC, 5)
+#define WLAN_CIPHER_SUITE_AES_CMAC     SUITE(0x000FAC, 6)
+#define WLAN_CIPHER_SUITE_GCMP         SUITE(0x000FAC, 8)
+#define WLAN_CIPHER_SUITE_GCMP_256     SUITE(0x000FAC, 9)
+#define WLAN_CIPHER_SUITE_CCMP_256     SUITE(0x000FAC, 10)
+#define WLAN_CIPHER_SUITE_BIP_GMAC_128 SUITE(0x000FAC, 11)
+#define WLAN_CIPHER_SUITE_BIP_GMAC_256 SUITE(0x000FAC, 12)
+#define WLAN_CIPHER_SUITE_BIP_CMAC_256 SUITE(0x000FAC, 13)
+
+#define WLAN_CIPHER_SUITE_SMS4         SUITE(0x001472, 1)
 
 /* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X           0x000FAC01
-#define WLAN_AKM_SUITE_PSK             0x000FAC02
-#define WLAN_AKM_SUITE_8021X_SHA256    0x000FAC05
-#define WLAN_AKM_SUITE_PSK_SHA256      0x000FAC06
-#define WLAN_AKM_SUITE_TDLS            0x000FAC07
-#define WLAN_AKM_SUITE_SAE             0x000FAC08
-#define WLAN_AKM_SUITE_FT_OVER_SAE     0x000FAC09
+#define WLAN_AKM_SUITE_8021X           SUITE(0x000FAC, 1)
+#define WLAN_AKM_SUITE_PSK             SUITE(0x000FAC, 2)
+#define WLAN_AKM_SUITE_8021X_SHA256    SUITE(0x000FAC, 5)
+#define WLAN_AKM_SUITE_PSK_SHA256      SUITE(0x000FAC, 6)
+#define WLAN_AKM_SUITE_TDLS            SUITE(0x000FAC, 7)
+#define WLAN_AKM_SUITE_SAE             SUITE(0x000FAC, 8)
+#define WLAN_AKM_SUITE_FT_OVER_SAE     SUITE(0x000FAC, 9)
+#define WLAN_AKM_SUITE_FILS_SHA256     SUITE(0x000FAC, 14)
+#define WLAN_AKM_SUITE_FILS_SHA384     SUITE(0x000FAC, 15)
+#define WLAN_AKM_SUITE_FT_FILS_SHA256  SUITE(0x000FAC, 16)
+#define WLAN_AKM_SUITE_FT_FILS_SHA384  SUITE(0x000FAC, 17)
 
 #define WLAN_MAX_KEY_LEN               32
 
index 55ae8b9..2767fcd 100644 (file)
@@ -235,6 +235,8 @@ struct iommu_ops {
        void (*tlbi_domain)(struct iommu_domain *domain);
        int (*enable_config_clocks)(struct iommu_domain *domain);
        void (*disable_config_clocks)(struct iommu_domain *domain);
+       uint64_t (*iova_to_pte)(struct iommu_domain *domain,
+                        dma_addr_t iova);
 
 #ifdef CONFIG_OF_IOMMU
        int (*of_xlate)(struct device *dev, struct of_phandle_args *args);
@@ -334,6 +336,9 @@ extern int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
                                      phys_addr_t offset, u64 size,
                                      int prot);
 extern void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr);
+
+extern uint64_t iommu_iova_to_pte(struct iommu_domain *domain,
+           dma_addr_t iova);
 /**
  * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
  * @domain: the iommu domain where the fault has happened
index 4b9f85c..0fdc798 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_KASAN_H
 #define _LINUX_KASAN_H
 
+#include <linux/sched.h>
 #include <linux/types.h>
 
 struct kmem_cache;
@@ -13,7 +14,6 @@ struct vm_struct;
 
 #include <asm/kasan.h>
 #include <asm/pgtable.h>
-#include <linux/sched.h>
 
 extern unsigned char kasan_zero_page[PAGE_SIZE];
 extern pte_t kasan_zero_pte[PTRS_PER_PTE];
@@ -43,6 +43,8 @@ static inline void kasan_disable_current(void)
 
 void kasan_unpoison_shadow(const void *address, size_t size);
 
+void kasan_unpoison_task_stack(struct task_struct *task);
+
 void kasan_alloc_pages(struct page *page, unsigned int order);
 void kasan_free_pages(struct page *page, unsigned int order);
 
@@ -66,6 +68,8 @@ void kasan_free_shadow(const struct vm_struct *vm);
 
 static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
 
+static inline void kasan_unpoison_task_stack(struct task_struct *task) {}
+
 static inline void kasan_enable_current(void) {}
 static inline void kasan_disable_current(void) {}
 
index c923350..d7ce4e3 100644 (file)
@@ -182,8 +182,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
                    int len, void *val);
 int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                            int len, struct kvm_io_device *dev);
-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
-                             struct kvm_io_device *dev);
+void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+                              struct kvm_io_device *dev);
 
 #ifdef CONFIG_KVM_ASYNC_PF
 struct kvm_async_pf {
diff --git a/include/linux/mbcache2.h b/include/linux/mbcache2.h
new file mode 100644 (file)
index 0000000..b6f160f
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _LINUX_MB2CACHE_H
+#define _LINUX_MB2CACHE_H
+
+#include <linux/hash.h>
+#include <linux/list_bl.h>
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/fs.h>
+
+struct mb2_cache;
+
+struct mb2_cache_entry {
+       /* LRU list - protected by cache->c_lru_list_lock */
+       struct list_head        e_lru_list;
+       /* Hash table list - protected by bitlock in e_hash_list_head */
+       struct hlist_bl_node    e_hash_list;
+       atomic_t                e_refcnt;
+       /* Key in hash - stable during lifetime of the entry */
+       u32                     e_key;
+       /* Block number of hashed block - stable during lifetime of the entry */
+       sector_t                e_block;
+       /* Head of hash list (for list bit lock) - stable */
+       struct hlist_bl_head    *e_hash_list_head;
+};
+
+struct mb2_cache *mb2_cache_create(int bucket_bits);
+void mb2_cache_destroy(struct mb2_cache *cache);
+
+int mb2_cache_entry_create(struct mb2_cache *cache, gfp_t mask, u32 key,
+                          sector_t block);
+void __mb2_cache_entry_free(struct mb2_cache_entry *entry);
+static inline int mb2_cache_entry_put(struct mb2_cache *cache,
+                                     struct mb2_cache_entry *entry)
+{
+       if (!atomic_dec_and_test(&entry->e_refcnt))
+               return 0;
+       __mb2_cache_entry_free(entry);
+       return 1;
+}
+
+void mb2_cache_entry_delete_block(struct mb2_cache *cache, u32 key,
+                                 sector_t block);
+struct mb2_cache_entry *mb2_cache_entry_find_first(struct mb2_cache *cache,
+                                                  u32 key);
+struct mb2_cache_entry *mb2_cache_entry_find_next(struct mb2_cache *cache,
+                                                 struct mb2_cache_entry *entry);
+void mb2_cache_entry_touch(struct mb2_cache *cache,
+                          struct mb2_cache_entry *entry);
+
+#endif /* _LINUX_MB2CACHE_H */
index 734169f..e4937bb 100644 (file)
@@ -523,6 +523,10 @@ struct mm_struct {
 #ifdef CONFIG_HUGETLB_PAGE
        atomic_long_t hugetlb_usage;
 #endif
+#ifdef CONFIG_MSM_APP_SETTINGS
+       int app_setting;
+#endif
+
 };
 
 static inline void mm_init_cpumask(struct mm_struct *mm)
index 0e9b097..b606d8f 100644 (file)
@@ -96,4 +96,6 @@ extern void mark_mounts_for_expiry(struct list_head *mounts);
 
 extern dev_t name_to_dev_t(const char *name);
 
+extern unsigned int sysctl_mount_max;
+
 #endif /* _LINUX_MOUNT_H */
index 7488bb9..aa8edf9 100644 (file)
@@ -247,6 +247,7 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
        POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
        POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+       POWER_SUPPLY_PROP_REAL_TYPE,
        /* Local extensions of type int64_t */
        POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
        /* Properties of type `const char *' */
diff --git a/include/linux/regulator/onsemi-ncp6335d.h b/include/linux/regulator/onsemi-ncp6335d.h
new file mode 100644 (file)
index 0000000..399742f
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __NCP6335D_H__
+#define __NCP6335D_H__
+
+enum {
+       NCP6335D_VSEL0,
+       NCP6335D_VSEL1,
+};
+
+struct ncp6335d_platform_data {
+       struct regulator_init_data *init_data;
+       int default_vsel;
+       int slew_rate_ns;
+       int discharge_enable;
+       bool sleep_enable;
+};
+
+#ifdef CONFIG_REGULATOR_ONSEMI_NCP6335D
+int __init ncp6335d_regulator_init(void);
+#else
+static inline int __init ncp6335d_regulator_init(void) { return 0; }
+#endif
+
+#endif
index 9cb0c17..c719784 100644 (file)
@@ -1647,6 +1647,10 @@ struct task_struct {
 #ifdef CONFIG_COMPAT_BRK
        unsigned brk_randomized:1;
 #endif
+#ifdef CONFIG_CGROUPS
+       /* disallow userland-initiated cgroup migration */
+       unsigned no_cgroup_migration:1;
+#endif
 
        unsigned long atomic_flags; /* Flags needing atomic access. */
 
index e9277e8..3d11c7d 100644 (file)
@@ -74,6 +74,11 @@ struct wiphy;
 #define CFG80211_CONNECT_TIMEOUT 1
 #define CFG80211_CONNECT_TIMEOUT_REASON_CODE 1
 
+/* Indicate backport support for the new connect done api */
+#define CFG80211_CONNECT_DONE 1
+/* Indicate backport support for FILS SK offload in cfg80211 */
+#define CFG80211_FILS_SK_OFFLOAD_SUPPORT 1
+
 /*
  * wireless hardware capability structures
  */
@@ -1833,6 +1838,12 @@ enum cfg80211_assoc_req_flags {
  * @ht_capa_mask:  The bits of ht_capa which are to be used.
  * @vht_capa: VHT capability override
  * @vht_capa_mask: VHT capability mask indicating which fields to use
+ * @fils_kek: FILS KEK for protecting (Re)Association Request/Response frame or
+ *     %NULL if FILS is not used.
+ * @fils_kek_len: Length of fils_kek in octets
+ * @fils_nonces: FILS nonces (part of AAD) for protecting (Re)Association
+ *     Request/Response frame or %NULL if FILS is not used. This field starts
+ *     with 16 octets of STA Nonce followed by 16 octets of AP Nonce.
  */
 struct cfg80211_assoc_request {
        struct cfg80211_bss *bss;
@@ -1844,6 +1855,9 @@ struct cfg80211_assoc_request {
        struct ieee80211_ht_cap ht_capa;
        struct ieee80211_ht_cap ht_capa_mask;
        struct ieee80211_vht_cap vht_capa, vht_capa_mask;
+       const u8 *fils_kek;
+       size_t fils_kek_len;
+       const u8 *fils_nonces;
 };
 
 /**
@@ -1991,7 +2005,20 @@ struct cfg80211_bss_selection {
  *     networks.
  * @bss_select: criteria to be used for BSS selection.
  * @prev_bssid: previous BSSID, if not %NULL use reassociate frame
- */
+ * @fils_erp_username: EAP re-authentication protocol (ERP) username part of the
+ *     NAI or %NULL if not specified. This is used to construct FILS wrapped
+ *     data IE.
+ * @fils_erp_username_len: Length of @fils_erp_username in octets.
+ * @fils_erp_realm: EAP re-authentication protocol (ERP) realm part of NAI or
+ *     %NULL if not specified. This specifies the domain name of ER server and
+ *     is used to construct FILS wrapped data IE.
+ * @fils_erp_realm_len: Length of @fils_erp_realm in octets.
+ * @fils_erp_next_seq_num: The next sequence number to use in the FILS ERP
+ *     messages. This is also used to construct FILS wrapped data IE.
+ * @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional
+ *     keys in FILS or %NULL if not specified.
+ * @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
+*/
 struct cfg80211_connect_params {
        struct ieee80211_channel *channel;
        struct ieee80211_channel *channel_hint;
@@ -2016,6 +2043,13 @@ struct cfg80211_connect_params {
        bool pbss;
        struct cfg80211_bss_selection bss_select;
        const u8 *prev_bssid;
+       const u8 *fils_erp_username;
+       size_t fils_erp_username_len;
+       const u8 *fils_erp_realm;
+       size_t fils_erp_realm_len;
+       u16 fils_erp_next_seq_num;
+       const u8 *fils_erp_rrk;
+       size_t fils_erp_rrk_len;
 };
 
 /**
@@ -2054,12 +2088,27 @@ enum wiphy_params_flags {
  * This structure is passed to the set/del_pmksa() method for PMKSA
  * caching.
  *
- * @bssid: The AP's BSSID.
- * @pmkid: The PMK material itself.
+ * @bssid: The AP's BSSID (may be %NULL).
+ * @pmkid: The identifier to refer a PMKSA.
+ * @pmk: The PMK for the PMKSA identified by @pmkid. This is used for key
+ *     derivation by a FILS STA. Otherwise, %NULL.
+ * @pmk_len: Length of the @pmk. The length of @pmk can differ depending on
+ *     the hash algorithm used to generate this.
+ * @ssid: SSID to specify the ESS within which a PMKSA is valid when using FILS
+ *     cache identifier (may be %NULL).
+ * @ssid_len: Length of the @ssid in octets.
+ * @cache_id: 2-octet cache identifier advertized by a FILS AP identifying the
+ *     scope of PMKSA. This is valid only if @ssid_len is non-zero (may be
+ *     %NULL).
  */
 struct cfg80211_pmksa {
        const u8 *bssid;
        const u8 *pmkid;
+       const u8 *pmk;
+       size_t pmk_len;
+       const u8 *ssid;
+       size_t ssid_len;
+       const u8 *cache_id;
 };
 
 /**
@@ -4819,6 +4868,78 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 #endif
 
 /**
+ * struct cfg80211_connect_resp_params - Connection response params
+ * @status: Status code, %WLAN_STATUS_SUCCESS for successful connection, use
+ *     %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ *     the real status code for failures. If this call is used to report a
+ *     failure due to a timeout (e.g., not receiving an Authentication frame
+ *     from the AP) instead of an explicit rejection by the AP, -1 is used to
+ *     indicate that this is a failure, but without a status code.
+ *     @timeout_reason is used to report the reason for the timeout in that
+ *     case.
+ * @bssid: The BSSID of the AP (may be %NULL)
+ * @bss: Entry of bss to which STA got connected to, can be obtained through
+ *     cfg80211_get_bss() (may be %NULL). Only one parameter among @bssid and
+ *     @bss needs to be specified.
+ * @req_ie: Association request IEs (may be %NULL)
+ * @req_ie_len: Association request IEs length
+ * @resp_ie: Association response IEs (may be %NULL)
+ * @resp_ie_len: Association response IEs length
+ * @fils_kek: KEK derived from a successful FILS connection (may be %NULL)
+ * @fils_kek_len: Length of @fils_kek in octets
+ * @update_erp_next_seq_num: Boolean value to specify whether the value in
+ *     @fils_erp_next_seq_num is valid.
+ * @fils_erp_next_seq_num: The next sequence number to use in ERP message in
+ *     FILS Authentication. This value should be specified irrespective of the
+ *     status for a FILS connection.
+ * @pmk: A new PMK if derived from a successful FILS connection (may be %NULL).
+ * @pmk_len: Length of @pmk in octets
+ * @pmkid: A new PMKID if derived from a successful FILS connection or the PMKID
+ *     used for this FILS connection (may be %NULL).
+ * @timeout_reason: Reason for connection timeout. This is used when the
+ *     connection fails due to a timeout instead of an explicit rejection from
+ *     the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is
+ *     not known. This value is used only if @status < 0 to indicate that the
+ *     failure is due to a timeout and not due to explicit rejection by the AP.
+ *     This value is ignored in other cases (@status >= 0).
+ */
+struct cfg80211_connect_resp_params {
+       int status;
+       const u8 *bssid;
+       struct cfg80211_bss *bss;
+       const u8 *req_ie;
+       size_t req_ie_len;
+       const u8 *resp_ie;
+       size_t resp_ie_len;
+       const u8 *fils_kek;
+       size_t fils_kek_len;
+       bool update_erp_next_seq_num;
+       u16 fils_erp_next_seq_num;
+       const u8 *pmk;
+       size_t pmk_len;
+       const u8 *pmkid;
+       enum nl80211_timeout_reason timeout_reason;
+};
+
+/**
+ * cfg80211_connect_done - notify cfg80211 of connection result
+ *
+ * @dev: network device
+ * @params: connection response parameters
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_bss(), but takes a structure pointer for connection response
+ * parameters. Only one of the functions among cfg80211_connect_bss(),
+ * cfg80211_connect_result(), cfg80211_connect_timeout(),
+ * and cfg80211_connect_done() should be called.
+ */
+void cfg80211_connect_done(struct net_device *dev,
+                          struct cfg80211_connect_resp_params *params,
+                          gfp_t gfp);
+
+/**
  * cfg80211_connect_bss - notify cfg80211 of connection result
  *
  * @dev: network device
@@ -4829,9 +4950,14 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
  * @req_ie_len: association request IEs length
  * @resp_ie: association response IEs (may be %NULL)
  * @resp_ie_len: assoc response IEs length
- * @status: status code, 0 for successful connection, use
- *      %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
- *      the real status code for failures.
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful connection, use
+ *     %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ *     the real status code for failures. If this call is used to report a
+ *     failure due to a timeout (e.g., not receiving an Authentication frame
+ *     from the AP) instead of an explicit rejection by the AP, -1 is used to
+ *     indicate that this is a failure, but without a status code.
+ *     @timeout_reason is used to report the reason for the timeout in that
+ *     case.
  * @gfp: allocation flags
  * @timeout_reason: reason for connection timeout. This is used when the
  *     connection fails due to a timeout instead of an explicit rejection from
@@ -4840,16 +4966,34 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
  *     failure is due to a timeout and not due to explicit rejection by the AP.
  *     This value is ignored in other cases (@status >= 0).
  *
- * It should be called by the underlying driver whenever connect() has
- * succeeded. This is similar to cfg80211_connect_result(), but with the
- * option of identifying the exact bss entry for the connection. Only one of
- * these functions should be called.
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_result(), but with the option of identifying the exact bss
+ * entry for the connection. Only one of the functions among
+ * cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
  */
-void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
-                         struct cfg80211_bss *bss, const u8 *req_ie,
-                         size_t req_ie_len, const u8 *resp_ie,
-                         size_t resp_ie_len, int status, gfp_t gfp,
-                         enum nl80211_timeout_reason timeout_reason);
+static inline void
+cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
+                    struct cfg80211_bss *bss, const u8 *req_ie,
+                    size_t req_ie_len, const u8 *resp_ie,
+                    size_t resp_ie_len, int status, gfp_t gfp,
+                    enum nl80211_timeout_reason timeout_reason)
+{
+       struct cfg80211_connect_resp_params params;
+
+       memset(&params, 0, sizeof(params));
+       params.status = status;
+       params.bssid = bssid;
+       params.bss = bss;
+       params.req_ie = req_ie;
+       params.req_ie_len = req_ie_len;
+       params.resp_ie = resp_ie;
+       params.resp_ie_len = resp_ie_len;
+       params.timeout_reason = timeout_reason;
+
+       cfg80211_connect_done(dev, &params, gfp);
+}
 
 /**
  * cfg80211_connect_result - notify cfg80211 of connection result
@@ -4860,13 +5004,16 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
  * @req_ie_len: association request IEs length
  * @resp_ie: association response IEs (may be %NULL)
  * @resp_ie_len: assoc response IEs length
- * @status: status code, 0 for successful connection, use
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful connection, use
  *     %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
  *     the real status code for failures.
  * @gfp: allocation flags
  *
- * It should be called by the underlying driver whenever connect() has
- * succeeded.
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_bss() which allows the exact bss entry to be specified. Only
+ * one of the functions among cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
  */
 static inline void
 cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -4893,7 +5040,9 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
  * in a sequence where no explicit authentication/association rejection was
  * received from the AP. This could happen, e.g., due to not being able to send
  * out the Authentication or Association Request frame or timing out while
- * waiting for the response.
+ * waiting for the response. Only one of the functions among
+ * cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
  */
 static inline void
 cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
index c81fc24..b76d567 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014,2016 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
  */
 
 #ifdef CONFIG_MSM_BOOT_STATS
+
+#define TIMER_KHZ 32768
+extern struct boot_stats __iomem *boot_stats;
+
+struct boot_stats {
+       uint32_t bootloader_start;
+       uint32_t bootloader_end;
+       uint32_t bootloader_display;
+       uint32_t bootloader_load_kernel;
+       uint32_t load_kernel_start;
+       uint32_t load_kernel_end;
+#ifdef CONFIG_MSM_BOOT_TIME_MARKER
+       uint32_t bootloader_early_domain_start;
+       uint32_t bootloader_checksum;
+#endif
+};
+
 int boot_stats_init(void);
+int boot_stats_exit(void);
+unsigned long long int msm_timer_get_sclk_ticks(void);
 #else
 static inline int boot_stats_init(void) { return 0; }
+unsigned long long int msm_timer_get_sclk_ticks(void) { return 0; }
+#endif
+
+#ifdef CONFIG_MSM_BOOT_TIME_MARKER
+
+static inline int boot_marker_enabled(void) { return 1; }
+void place_marker(const char *name);
+#else
+inline void place_marker(char *name);
+static inline int boot_marker_enabled(void) { return 0; }
 #endif
index 9d993a1..2db61a4 100644 (file)
@@ -37,7 +37,7 @@ struct md_region {
  */
 #ifdef CONFIG_QCOM_MINIDUMP
 extern int msm_minidump_add_region(const struct md_region *entry);
-extern bool msm_minidump_enabled(void);
+extern bool minidump_enabled;
 #else
 static inline int msm_minidump_add_region(const struct md_region *entry)
 {
index c53b510..ffcf6ec 100644 (file)
 
 struct profiler_bw_cntrs_req {
        uint32_t total;
-       uint32_t gpu;
        uint32_t cpu;
+       uint32_t gpu;
        uint32_t cmd;
 };
 
 struct compat_profiler_bw_cntrs_req {
        compat_uint_t total;
-       compat_uint_t gpu;
        compat_uint_t cpu;
+       compat_uint_t gpu;
        compat_uint_t cmd;
 };
 
index dfb0280..2e8d717 100644 (file)
@@ -84,8 +84,6 @@
        of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmtellurium")
 #define early_machine_is_msm8996()     \
        of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8996")
-#define early_machine_is_msm8996_auto()        \
-       of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8996-cdp")
 #define early_machine_is_msm8929()     \
        of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8929")
 #define early_machine_is_msm8998()     \
index 5974921..b08cc7d 100644 (file)
@@ -56,6 +56,8 @@ struct module;
  * @sysmon_shutdown_ret: Return value for the call to sysmon_send_shutdown
  * @system_debug: If "set", triggers a device restart when the
  * subsystem's wdog bite handler is invoked.
+ * @ignore_ssr_failure: SSR failures are usually fatal and results in panic. If
+ * set will ignore failure.
  * @edge: GLINK logical name of the subsystem
  */
 struct subsys_desc {
@@ -91,6 +93,7 @@ struct subsys_desc {
        u32 sysmon_pid;
        int sysmon_shutdown_ret;
        bool system_debug;
+       bool ignore_ssr_failure;
        const char *edge;
 };
 
diff --git a/include/sound/msm-dts-eagle.h b/include/sound/msm-dts-eagle.h
deleted file mode 100644 (file)
index 2ef0113..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MSM_DTS_EAGLE_H__
-#define __MSM_DTS_EAGLE_H__
-
-#include <linux/compat.h>
-#include <sound/soc.h>
-#include <sound/devdep_params.h>
-#include <sound/q6asm-v2.h>
-
-#ifdef CONFIG_COMPAT
-enum {
-       DTS_EAGLE_IOCTL_GET_CACHE_SIZE32 = _IOR(0xF2, 0, __s32),
-       DTS_EAGLE_IOCTL_SET_CACHE_SIZE32 = _IOW(0xF2, 1, __s32),
-       DTS_EAGLE_IOCTL_GET_PARAM32 = _IOR(0xF2, 2, compat_uptr_t),
-       DTS_EAGLE_IOCTL_SET_PARAM32 = _IOW(0xF2, 3, compat_uptr_t),
-       DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32 =
-                               _IOW(0xF2, 4, compat_uptr_t),
-       DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32 =
-                               _IOW(0xF2, 5, compat_uptr_t),
-       DTS_EAGLE_IOCTL_GET_LICENSE32 =
-                               _IOR(0xF2, 6, compat_uptr_t),
-       DTS_EAGLE_IOCTL_SET_LICENSE32 =
-                                _IOW(0xF2, 7, compat_uptr_t),
-       DTS_EAGLE_IOCTL_SEND_LICENSE32 = _IOW(0xF2, 8, __s32),
-       DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32 = _IOW(0xF2, 9,
-                                                    compat_uptr_t),
-};
-#endif
-
-#ifdef CONFIG_DTS_EAGLE
-void msm_dts_ion_memmap(struct param_outband *po_);
-int msm_dts_eagle_enable_asm(struct audio_client *ac, u32 enable, int module);
-int msm_dts_eagle_enable_adm(int port_id, int copp_idx, u32 enable);
-void msm_dts_eagle_add_controls(struct snd_soc_platform *platform);
-int msm_dts_eagle_set_stream_gain(struct audio_client *ac,
-                                 int lgain, int rgain);
-int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd, char *buf,
-                            bool for_pre, bool get, struct audio_client *ac,
-                            struct param_outband *po);
-int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd, char *buf,
-                            bool for_pre, bool get);
-int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg);
-int msm_dts_eagle_is_hpx_on(void);
-int msm_dts_eagle_init_pre(struct audio_client *ac);
-int msm_dts_eagle_deinit_pre(struct audio_client *ac);
-int msm_dts_eagle_init_post(int port_id, int copp_id);
-int msm_dts_eagle_deinit_post(int port_id, int topology);
-int msm_dts_eagle_init_master_module(struct audio_client *ac);
-int msm_dts_eagle_deinit_master_module(struct audio_client *ac);
-int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime);
-void msm_dts_eagle_pcm_free(struct snd_pcm *pcm);
-int msm_dts_eagle_compat_ioctl(unsigned int cmd, unsigned long arg);
-#else
-static inline void msm_dts_ion_memmap(struct param_outband *po_)
-{
-       pr_debug("%s\n", __func__);
-}
-static inline int msm_dts_eagle_enable_asm(struct audio_client *ac,
-                                          u32 enable, int module)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_enable_adm(int port_id, int copp_idx,
-                                          u32 enable)
-{
-       return 0;
-}
-static inline void msm_dts_eagle_add_controls(struct snd_soc_platform *platform)
-{
-}
-static inline int msm_dts_eagle_set_stream_gain(struct audio_client *ac,
-                                               int lgain, int rgain)
-{
-       pr_debug("%s\n", __func__);
-       return 0;
-}
-static inline int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd,
-                                          char *buf, bool for_pre, bool get,
-                                          struct audio_client *ac,
-                                          struct param_outband *po)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd,
-                                          char *buf, bool for_pre, bool get)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg)
-{
-       return -EPERM;
-}
-static inline int msm_dts_eagle_is_hpx_on(void)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_init_pre(struct audio_client *ac)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_deinit_pre(struct audio_client *ac)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_init_post(int port_id, int coppid)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_deinit_post(int port_id, int topology)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_init_master_module(struct audio_client *ac)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_deinit_master_module(struct audio_client *ac)
-{
-       return 0;
-}
-static inline int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime)
-{
-       pr_debug("%s\n", __func__);
-       return 0;
-}
-static inline void msm_dts_eagle_pcm_free(struct snd_pcm *pcm)
-{
-       pr_debug("%s\n", __func__);
-}
-static inline int msm_dts_eagle_compat_ioctl(unsigned int cmd,
-                                       unsigned long arg)
-{
-       return 0;
-}
-#endif
-
-#endif
index f3443b7..caabb66 100644 (file)
@@ -34,7 +34,6 @@ enum {
        ADM_AUDVOL_CAL,
        ADM_RTAC_INFO_CAL,
        ADM_RTAC_APR_CAL,
-       ADM_DTS_EAGLE,
        ADM_SRS_TRUMEDIA,
        ADM_RTAC_AUDVOL_CAL,
        ADM_MAX_CAL_TYPES
index 7586072..ad19e73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete,
        TP_ARGS(core, phase)
 );
 
+DECLARE_EVENT_CLASS(clk_state_dump,
+
+       TP_PROTO(const char *name, unsigned int prepare_count,
+       unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+       TP_ARGS(name, prepare_count, enable_count, rate, vdd_level),
+
+       TP_STRUCT__entry(
+               __string(name,                  name)
+               __field(unsigned int,           prepare_count)
+               __field(unsigned int,           enable_count)
+               __field(unsigned long,          rate)
+               __field(unsigned int,           vdd_level)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->prepare_count = prepare_count;
+               __entry->enable_count = enable_count;
+               __entry->rate = rate;
+               __entry->vdd_level = vdd_level;
+       ),
+
+       TP_printk("%s\tprepare:enable cnt [%u:%u]\trate: vdd_level [%lu:%u]",
+               __get_str(name), __entry->prepare_count, __entry->enable_count,
+               __entry->rate, __entry->vdd_level)
+);
+
+DEFINE_EVENT(clk_state_dump, clk_state,
+
+       TP_PROTO(const char *name, unsigned int prepare_count,
+       unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+       TP_ARGS(name, prepare_count, enable_count, rate, vdd_level)
+);
+
 #endif /* _TRACE_CLK_H */
 
 /* This part must be outside protection */
index c974714..db65513 100644 (file)
@@ -323,6 +323,18 @@ struct drm_msm_counter_read {
        __u32 nr_ops;
 };
 
+#define MSM_GEM_SYNC_TO_DEV 0
+#define MSM_GEM_SYNC_TO_CPU 1
+
+struct drm_msm_gem_syncop {
+       __u32 handle;
+       __u32 op;
+};
+
+struct drm_msm_gem_sync {
+       __u32 nr_ops;
+       __u64 __user ops;
+};
 
 #define DRM_MSM_GET_PARAM              0x00
 /* placeholder:
@@ -341,6 +353,7 @@ struct drm_msm_counter_read {
 #define DRM_MSM_COUNTER_GET            0x43
 #define DRM_MSM_COUNTER_PUT            0x44
 #define DRM_MSM_COUNTER_READ           0x45
+#define DRM_MSM_GEM_SYNC               0x46
 
 /**
  * Currently DRM framework supports only VSYNC event.
@@ -370,5 +383,6 @@ struct drm_msm_counter_read {
 #define DRM_IOCTL_MSM_COUNTER_READ \
        DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_COUNTER_READ, \
                struct drm_msm_counter_read)
-
+#define DRM_IOCTL_MSM_GEM_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_GEM_SYNC,\
+               struct drm_msm_gem_sync)
 #endif /* __MSM_DRM_H__ */
index 57266ed..c0680f3 100644 (file)
@@ -7,6 +7,7 @@
 #define ESOC_WAIT_FOR_REQ      _IOR(ESOC_CODE, 2, unsigned int)
 #define ESOC_NOTIFY            _IOW(ESOC_CODE, 3, unsigned int)
 #define ESOC_GET_STATUS                _IOR(ESOC_CODE, 4, unsigned int)
+#define ESOC_GET_ERR_FATAL     _IOR(ESOC_CODE, 5, unsigned int)
 #define ESOC_WAIT_FOR_CRASH    _IOR(ESOC_CODE, 6, unsigned int)
 #define ESOC_REG_REQ_ENG       _IO(ESOC_CODE, 7)
 #define ESOC_REG_CMD_ENG       _IO(ESOC_CODE, 8)
@@ -15,6 +16,7 @@
 #define HSIC           "HSIC"
 #define HSICPCIe       "HSIC+PCIe"
 #define PCIe           "PCIe"
+#define ESOC_REQ_SEND_SHUTDOWN ESOC_REQ_SEND_SHUTDOWN
 
 enum esoc_evt {
        ESOC_RUN_STATE = 0x1,
@@ -55,6 +57,7 @@ enum esoc_req {
        ESOC_REQ_IMG = 1,
        ESOC_REQ_DEBUG,
        ESOC_REQ_SHUTDOWN,
+       ESOC_REQ_SEND_SHUTDOWN,
 };
 
 #ifdef __KERNEL__
index 960aa84..3dd0091 100644 (file)
  */
 
 /**
+ * DOC: FILS shared key authentication offload
+ *
+ * FILS shared key authentication offload can be advertized by drivers by
+ * setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support
+ * FILS shared key authentication offload should be able to construct the
+ * authentication and association frames for FILS shared key authentication and
+ * eventually do a key derivation as per IEEE 802.11ai. The below additional
+ * parameters should be given to driver in %NL80211_CMD_CONNECT.
+ *     %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
+ *     %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
+ *     %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
+ *     %NL80211_ATTR_FILS_ERP_RRK - used to generate the rIK and rMSK
+ * rIK should be used to generate an authentication tag on the ERP message and
+ * rMSK should be used to derive a PMKSA.
+ * rIK, rMSK should be generated and keyname_nai, sequence number should be used
+ * as specified in IETF RFC 6696.
+ *
+ * When FILS shared key authentication is completed, driver needs to provide the
+ * below additional parameters to userspace.
+ *     %NL80211_ATTR_FILS_KEK - used for key renewal
+ *     %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
+ *     %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
+ *     %Nl80211_ATTR_PMK - used to update PMKSA cache in userspace
+ * The PMKSA can be maintained in userspace persistently so that it can be used
+ * later after reboots or wifi turn off/on also.
+ *
+ * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS
+ * capable AP supporting PMK caching. It specifies the scope within which the
+ * PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and
+ * %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based
+ * on FILS cache identifier. Additionally %NL80211_ATTR_PMK is used with
+ * %NL80211_SET_PMKSA to specify the PMK corresponding to a PMKSA for driver to
+ * use in a FILS shared key connection with PMKSA caching.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
  *     NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
  *
- * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
- *     (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry using %NL80211_ATTR_MAC
+ *     (for the BSSID), %NL80211_ATTR_PMKID, and optionally %NL80211_ATTR_PMK
+ *     (PMK is used for PTKSA derivation in case of FILS shared key offload) or
+ *     using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID,
+ *     %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS
+ *     authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier
+ *     advertized by a FILS capable AP identifying the scope of PMKSA in an
+ *     ESS.
  * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
- *     (for the BSSID) and %NL80211_ATTR_PMKID.
+ *     (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID,
+ *     %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS
+ *     authentication.
  * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
  *
  * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
@@ -1965,6 +2009,31 @@ enum nl80211_commands {
  *     u32 attribute with an &enum nl80211_timeout_reason value. This is used,
  *     e.g., with %NL80211_CMD_CONNECT event.
  *
+ * @NL80211_ATTR_FILS_ERP_USERNAME: EAP Re-authentication Protocol (ERP)
+ *     username part of NAI used to refer keys rRK and rIK. This is used with
+ *     %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_REALM: EAP Re-authentication Protocol (ERP) realm part
+ *     of NAI specifying the domain name of the ER server. This is used with
+ *     %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM: Unsigned 16-bit ERP next sequence number
+ *     to use in ERP messages. This is used in generating the FILS wrapped data
+ *     for FILS authentication and is used with %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_RRK: ERP re-authentication Root Key (rRK) for the
+ *     NAI specified by %NL80211_ATTR_FILS_ERP_USERNAME and
+ *     %NL80211_ATTR_FILS_ERP_REALM. This is used for generating rIK and rMSK
+ *     from successful FILS authentication and is used with
+ *     %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP
+ *     identifying the scope of PMKSAs. This is used with
+ *     @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
+ *
+ * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
+ *     This is used with @NL80211_CMD_SET_PMKSA.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2376,6 +2445,14 @@ enum nl80211_attrs {
 
        NL80211_ATTR_TIMEOUT_REASON,
 
+       NL80211_ATTR_FILS_ERP_USERNAME,
+       NL80211_ATTR_FILS_ERP_REALM,
+       NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+       NL80211_ATTR_FILS_ERP_RRK,
+       NL80211_ATTR_FILS_CACHE_ID,
+
+       NL80211_ATTR_PMK,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -3856,7 +3933,10 @@ enum nl80211_ps_state {
  * @__NL80211_ATTR_CQM_INVALID: invalid
  * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
  *     the threshold for the RSSI level at which an event will be sent. Zero
- *     to disable.
+ *     to disable.  Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is
+ *     set, multiple values can be supplied as a low-to-high sorted array of
+ *     threshold values in dBm.  Events will be sent when the RSSI value
+ *     crosses any of the thresholds.
  * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
  *     the minimum amount the RSSI level must change after an event before a
  *     new event may be issued (to reduce effects of RSSI oscillation).
@@ -4664,6 +4744,11 @@ enum nl80211_feature_flags {
  * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
  *     for reporting BSSs with better RSSI than the current connected BSS
  *     (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
+ * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the
+ *     %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more
+ *     RSSI threshold values to monitor rather than exactly one threshold.
+ * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
+ *     authentication with %NL80211_CMD_CONNECT.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4682,6 +4767,8 @@ enum nl80211_ext_feature_index {
        NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
        NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
        NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
+       NL80211_EXT_FEATURE_CQM_RSSI_LIST,
+       NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
index c3a6e00..d532037 100644 (file)
@@ -112,6 +112,7 @@ struct msm_ispif_param_data_ext {
        struct msm_ispif_pack_cfg pack_cfg[CID_MAX];
        struct msm_ispif_right_param_entry right_entries[MAX_PARAM_ENTRIES];
        uint32_t stereo_enable;
+       uint16_t line_width[VFE_MAX];
 };
 
 struct msm_ispif_param_data {
@@ -143,6 +144,7 @@ enum ispif_cfg_type_t {
        ISPIF_ENABLE_REG_DUMP,
        ISPIF_SET_VFE_INFO,
        ISPIF_CFG2,
+       ISPIF_CFG_STEREO,
 };
 
 struct ispif_cfg_data {
@@ -165,6 +167,8 @@ struct ispif_cfg_data_ext {
 
 #define ISPIF_3D_SUPPORT 1
 
+#define ISPIF_LINE_WIDTH_SUPPORT 1
+
 #define VIDIOC_MSM_ISPIF_CFG \
        _IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data)
 
index b05fc20..25cf448 100644 (file)
@@ -2693,7 +2693,7 @@ static int cgroup_procs_write_permission(struct task_struct *task,
        if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
            !uid_eq(cred->euid, tcred->uid) &&
            !uid_eq(cred->euid, tcred->suid) &&
-           !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
+           !ns_capable(tcred->user_ns, CAP_SYS_NICE))
                ret = -EACCES;
 
        if (!ret && cgroup_on_dfl(dst_cgrp)) {
@@ -2757,11 +2757,12 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
                tsk = tsk->group_leader;
 
        /*
-        * Workqueue threads may acquire PF_NO_SETAFFINITY and become
-        * trapped in a cpuset, or RT worker may be born in a cgroup
-        * with no rt_runtime allocated.  Just say no.
+        * kthreads may acquire PF_NO_SETAFFINITY during initialization.
+        * If userland migrates such a kthread to a non-root cgroup, it can
+        * become trapped in a cpuset, or RT kthread may be born in a
+        * cgroup with no rt_runtime allocated.  Just say no.
         */
-       if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
+       if (tsk->no_cgroup_migration || (tsk->flags & PF_NO_SETAFFINITY)) {
                ret = -EINVAL;
                goto out_unlock_rcu;
        }
index 06db8b6..95c447e 100644 (file)
@@ -8454,6 +8454,37 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
        return 0;
 }
 
+/*
+ * Variation on perf_event_ctx_lock_nested(), except we take two context
+ * mutexes.
+ */
+static struct perf_event_context *
+__perf_event_ctx_lock_double(struct perf_event *group_leader,
+                            struct perf_event_context *ctx)
+{
+       struct perf_event_context *gctx;
+
+again:
+       rcu_read_lock();
+       gctx = READ_ONCE(group_leader->ctx);
+       if (!atomic_inc_not_zero(&gctx->refcount)) {
+               rcu_read_unlock();
+               goto again;
+       }
+       rcu_read_unlock();
+
+       mutex_lock_double(&gctx->mutex, &ctx->mutex);
+
+       if (group_leader->ctx != gctx) {
+               mutex_unlock(&ctx->mutex);
+               mutex_unlock(&gctx->mutex);
+               put_ctx(gctx);
+               goto again;
+       }
+
+       return gctx;
+}
+
 /**
  * sys_perf_event_open - open a performance event, associate it to a task/cpu
  *
@@ -8707,8 +8738,26 @@ SYSCALL_DEFINE5(perf_event_open,
        }
 
        if (move_group) {
-               gctx = group_leader->ctx;
-               mutex_lock_double(&gctx->mutex, &ctx->mutex);
+               gctx = __perf_event_ctx_lock_double(group_leader, ctx);
+
+               /*
+                * Check if we raced against another sys_perf_event_open() call
+                * moving the software group underneath us.
+                */
+               if (!(group_leader->group_flags & PERF_GROUP_SOFTWARE)) {
+                       /*
+                        * If someone moved the group out from under us, check
+                        * if this new event wound up on the same ctx, if so
+                        * its the regular !move_group case, otherwise fail.
+                        */
+                       if (gctx != ctx) {
+                               err = -EINVAL;
+                               goto err_locked;
+                       } else {
+                               perf_event_ctx_unlock(group_leader, gctx);
+                               move_group = 0;
+                       }
+               }
        } else {
                mutex_lock(&ctx->mutex);
        }
@@ -8803,7 +8852,7 @@ SYSCALL_DEFINE5(perf_event_open,
        perf_unpin_context(ctx);
 
        if (move_group)
-               mutex_unlock(&gctx->mutex);
+               perf_event_ctx_unlock(group_leader, gctx);
        mutex_unlock(&ctx->mutex);
        if (group_leader)
                mutex_unlock(&group_leader->group_leader_mutex);
@@ -8833,7 +8882,7 @@ SYSCALL_DEFINE5(perf_event_open,
 
 err_locked:
        if (move_group)
-               mutex_unlock(&gctx->mutex);
+               perf_event_ctx_unlock(group_leader, gctx);
        mutex_unlock(&ctx->mutex);
 /* err_file: */
        fput(event_file);
index 9ff173d..850b255 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/freezer.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
+#include <linux/cgroup.h>
 #include <trace/events/sched.h>
 
 static DEFINE_SPINLOCK(kthread_create_lock);
@@ -205,6 +206,7 @@ static int kthread(void *_create)
        ret = -EINTR;
 
        if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
+               cgroup_kthread_ready();
                __kthread_parkme(&self);
                ret = threadfn(data);
        }
@@ -510,6 +512,7 @@ int kthreadd(void *unused)
        set_mems_allowed(node_states[N_MEMORY]);
 
        current->flags |= PF_NOFREEZE;
+       cgroup_init_kthreadd();
 
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
index b38bea9..401227e 100644 (file)
@@ -189,19 +189,20 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd)
 
        reorder = &next_queue->reorder;
 
+       spin_lock(&reorder->lock);
        if (!list_empty(&reorder->list)) {
                padata = list_entry(reorder->list.next,
                                    struct padata_priv, list);
 
-               spin_lock(&reorder->lock);
                list_del_init(&padata->list);
                atomic_dec(&pd->reorder_objects);
-               spin_unlock(&reorder->lock);
 
                pd->processed++;
 
+               spin_unlock(&reorder->lock);
                goto out;
        }
+       spin_unlock(&reorder->lock);
 
        if (__this_cpu_read(pd->pqueue->cpu_index) == next_queue->cpu_index) {
                padata = ERR_PTR(-ENODATA);
index 2fc1177..1535c46 100644 (file)
@@ -647,7 +647,7 @@ static void power_down(void)
  */
 int hibernate(void)
 {
-       int error;
+       int error, nr_calls = 0;
 
        if (!hibernation_available()) {
                pr_debug("PM: Hibernation not available.\n");
@@ -662,9 +662,11 @@ int hibernate(void)
        }
 
        pm_prepare_console();
-       error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
-       if (error)
+       error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
+       if (error) {
+               nr_calls--;
                goto Exit;
+       }
 
        printk(KERN_INFO "PM: Syncing filesystems ... ");
        sys_sync();
@@ -714,7 +716,7 @@ int hibernate(void)
        /* Don't bother checking whether freezer_test_done is true */
        freezer_test_done = false;
  Exit:
-       pm_notifier_call_chain(PM_POST_HIBERNATION);
+       __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL);
        pm_restore_console();
        atomic_inc(&snapshot_device_available);
  Unlock:
@@ -740,7 +742,7 @@ int hibernate(void)
  */
 static int software_resume(void)
 {
-       int error;
+       int error, nr_calls = 0;
        unsigned int flags;
 
        /*
@@ -827,9 +829,11 @@ static int software_resume(void)
        }
 
        pm_prepare_console();
-       error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
-       if (error)
+       error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
+       if (error) {
+               nr_calls--;
                goto Close_Finish;
+       }
 
        pr_debug("PM: Preparing processes for restore.\n");
        error = freeze_processes();
@@ -855,7 +859,7 @@ static int software_resume(void)
        unlock_device_hotplug();
        thaw_processes();
  Finish:
-       pm_notifier_call_chain(PM_POST_RESTORE);
+       __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
        pm_restore_console();
        atomic_inc(&snapshot_device_available);
        /* For success case, the suspend path will release the lock */
index 2794697..5ea50b1 100644 (file)
@@ -38,12 +38,19 @@ int unregister_pm_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(unregister_pm_notifier);
 
-int pm_notifier_call_chain(unsigned long val)
+int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls)
 {
-       int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
+       int ret;
+
+       ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL,
+                                               nr_to_call, nr_calls);
 
        return notifier_to_errno(ret);
 }
+int pm_notifier_call_chain(unsigned long val)
+{
+       return __pm_notifier_call_chain(val, -1, NULL);
+}
 
 /* If set, devices may be suspended and resumed asynchronously. */
 int pm_async_enabled = 1;
index efe1b3b..51f02ec 100644 (file)
@@ -200,6 +200,8 @@ static inline void suspend_test_finish(const char *label) {}
 
 #ifdef CONFIG_PM_SLEEP
 /* kernel/power/main.c */
+extern int __pm_notifier_call_chain(unsigned long val, int nr_to_call,
+                                   int *nr_calls);
 extern int pm_notifier_call_chain(unsigned long val);
 #endif
 
index 0244118..58209d8 100644 (file)
@@ -268,16 +268,18 @@ static int suspend_test(int level)
  */
 static int suspend_prepare(suspend_state_t state)
 {
-       int error;
+       int error, nr_calls = 0;
 
        if (!sleep_state_supported(state))
                return -EPERM;
 
        pm_prepare_console();
 
-       error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
-       if (error)
+       error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls);
+       if (error) {
+               nr_calls--;
                goto Finish;
+       }
 
        trace_suspend_resume(TPS("freeze_processes"), 0, true);
        error = suspend_freeze_processes();
@@ -288,7 +290,7 @@ static int suspend_prepare(suspend_state_t state)
        suspend_stats.failed_freeze++;
        dpm_save_failed_step(SUSPEND_FREEZE);
  Finish:
-       pm_notifier_call_chain(PM_POST_SUSPEND);
+       __pm_notifier_call_chain(PM_POST_SUSPEND, nr_calls, NULL);
        pm_restore_console();
        return error;
 }
index 526e891..35310b6 100644 (file)
@@ -47,7 +47,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1);
 static int snapshot_open(struct inode *inode, struct file *filp)
 {
        struct snapshot_data *data;
-       int error;
+       int error, nr_calls = 0;
 
        if (!hibernation_available())
                return -EPERM;
@@ -74,9 +74,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                        swap_type_of(swsusp_resume_device, 0, NULL) : -1;
                data->mode = O_RDONLY;
                data->free_bitmaps = false;
-               error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+               error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
                if (error)
-                       pm_notifier_call_chain(PM_POST_HIBERNATION);
+                       __pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL);
        } else {
                /*
                 * Resuming.  We may need to wait for the image device to
@@ -86,13 +86,15 @@ static int snapshot_open(struct inode *inode, struct file *filp)
 
                data->swap = -1;
                data->mode = O_WRONLY;
-               error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+               error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
                if (!error) {
                        error = create_basic_memory_bitmaps();
                        data->free_bitmaps = !error;
-               }
+               } else
+                       nr_calls--;
+
                if (error)
-                       pm_notifier_call_chain(PM_POST_RESTORE);
+                       __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
        }
        if (error)
                atomic_inc(&snapshot_device_available);
index a46c40b..c7e8ed9 100644 (file)
@@ -151,11 +151,17 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
 
        WARN_ON(!task->ptrace || task->parent != current);
 
+       /*
+        * PTRACE_LISTEN can allow ptrace_trap_notify to wake us up remotely.
+        * Recheck state under the lock to close this race.
+        */
        spin_lock_irq(&task->sighand->siglock);
-       if (__fatal_signal_pending(task))
-               wake_up_state(task, __TASK_TRACED);
-       else
-               task->state = TASK_TRACED;
+       if (task->state == __TASK_TRACED) {
+               if (__fatal_signal_pending(task))
+                       wake_up_state(task, __TASK_TRACED);
+               else
+                       task->state = TASK_TRACED;
+       }
        spin_unlock_irq(&task->sighand->siglock);
 }
 
index e107c4d..2d2b883 100644 (file)
@@ -26,6 +26,7 @@
  *              Thomas Gleixner, Mike Kravetz
  */
 
+#include <linux/kasan.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/nmi.h>
@@ -84,6 +85,9 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #endif
+#ifdef CONFIG_MSM_APP_SETTINGS
+#include <asm/app_api.h>
+#endif
 
 #include "sched.h"
 #include "../workqueue_internal.h"
@@ -2749,6 +2753,14 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
        fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
+
+#ifdef CONFIG_MSM_APP_SETTINGS
+       if (use_app_setting)
+               switch_app_setting_bit(prev, next);
+
+       if (use_32bit_app_setting || use_32bit_app_setting_pro)
+               switch_32bit_app_setting_bit(prev, next);
+#endif
 }
 
 /**
@@ -5413,6 +5425,8 @@ void init_idle(struct task_struct *idle, int cpu, bool cpu_up)
        idle->state = TASK_RUNNING;
        idle->se.exec_start = sched_clock();
 
+       kasan_unpoison_task_stack(idle);
+
 #ifdef CONFIG_SMP
        /*
         * Its possible that init_idle() gets called multiple times on a task,
index 8cc5167..8169998 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/sched/sysctl.h>
 #include <linux/kexec.h>
 #include <linux/bpf.h>
+#include <linux/mount.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -2077,6 +2078,14 @@ static struct ctl_table fs_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_doulongvec_minmax,
        },
+       {
+               .procname       = "mount-max",
+               .data           = &sysctl_mount_max,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
+       },
        { }
 };
 
index 3f743b1..34b2a0d 100644 (file)
@@ -3677,23 +3677,24 @@ static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash)
        ftrace_probe_registered = 1;
 }
 
-static void __disable_ftrace_function_probe(void)
+static bool __disable_ftrace_function_probe(void)
 {
        int i;
 
        if (!ftrace_probe_registered)
-               return;
+               return false;
 
        for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
                struct hlist_head *hhd = &ftrace_func_hash[i];
                if (hhd->first)
-                       return;
+                       return false;
        }
 
        /* no more funcs left */
        ftrace_shutdown(&trace_probe_ops, 0);
 
        ftrace_probe_registered = 0;
+       return true;
 }
 
 
@@ -3820,6 +3821,7 @@ static void
 __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                                  void *data, int flags)
 {
+       struct ftrace_ops_hash old_hash_ops;
        struct ftrace_func_entry *rec_entry;
        struct ftrace_func_probe *entry;
        struct ftrace_func_probe *p;
@@ -3831,6 +3833,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        struct hlist_node *tmp;
        char str[KSYM_SYMBOL_LEN];
        int i, ret;
+       bool disabled;
 
        if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
                func_g.search = NULL;
@@ -3849,6 +3852,10 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
        mutex_lock(&trace_probe_ops.func_hash->regex_lock);
 
+       old_hash_ops.filter_hash = old_hash;
+       /* Probes only have filters */
+       old_hash_ops.notrace_hash = NULL;
+
        hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
        if (!hash)
                /* Hmm, should report this somehow */
@@ -3886,12 +3893,17 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                }
        }
        mutex_lock(&ftrace_lock);
-       __disable_ftrace_function_probe();
+       disabled = __disable_ftrace_function_probe();
        /*
         * Remove after the disable is called. Otherwise, if the last
         * probe is removed, a null hash means *all enabled*.
         */
        ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+
+       /* still need to update the function call sites */
+       if (ftrace_enabled && !disabled)
+               ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
+                                      &old_hash_ops);
        synchronize_sched();
        if (!ret)
                free_ftrace_hash_rcu(old_hash);
index acbb0e7..1275175 100644 (file)
@@ -3440,11 +3440,23 @@ EXPORT_SYMBOL_GPL(ring_buffer_iter_reset);
 int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
+       struct buffer_page *reader;
+       struct buffer_page *head_page;
+       struct buffer_page *commit_page;
+       unsigned commit;
 
        cpu_buffer = iter->cpu_buffer;
 
-       return iter->head_page == cpu_buffer->commit_page &&
-               iter->head == rb_commit_index(cpu_buffer);
+       /* Remember, trace recording is off when iterator is in use */
+       reader = cpu_buffer->reader_page;
+       head_page = cpu_buffer->head_page;
+       commit_page = cpu_buffer->commit_page;
+       commit = rb_page_commit(commit_page);
+
+       return ((iter->head_page == commit_page && iter->head == commit) ||
+               (iter->head_page == reader && commit_page == head_page &&
+                head_page->read == commit &&
+                iter->head == rb_page_commit(cpu_buffer->reader_page)));
 }
 EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
 
@@ -4875,9 +4887,9 @@ static __init int test_ringbuffer(void)
                rb_data[cpu].cnt = cpu;
                rb_threads[cpu] = kthread_create(rb_test, &rb_data[cpu],
                                                 "rbtester/%d", cpu);
-               if (WARN_ON(!rb_threads[cpu])) {
+               if (WARN_ON(IS_ERR(rb_threads[cpu]))) {
                        pr_cont("FAILED\n");
-                       ret = -1;
+                       ret = PTR_ERR(rb_threads[cpu]);
                        goto out_free;
                }
 
@@ -4887,9 +4899,9 @@ static __init int test_ringbuffer(void)
 
        /* Now create the rb hammer! */
        rb_hammer = kthread_run(rb_hammer_test, NULL, "rbhammer");
-       if (WARN_ON(!rb_hammer)) {
+       if (WARN_ON(IS_ERR(rb_hammer))) {
                pr_cont("FAILED\n");
-               ret = -1;
+               ret = PTR_ERR(rb_hammer);
                goto out_free;
        }
 
index c0c10a3..60d246c 100644 (file)
@@ -6170,11 +6170,13 @@ ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
                return ret;
 
  out_reg:
-       ret = register_ftrace_function_probe(glob, ops, count);
+       ret = alloc_snapshot(&global_trace);
+       if (ret < 0)
+               goto out;
 
-       if (ret >= 0)
-               alloc_snapshot(&global_trace);
+       ret = register_ftrace_function_probe(glob, ops, count);
 
+ out:
        return ret < 0 ? ret : 0;
 }
 
index ea11123..7294301 100644 (file)
@@ -4362,6 +4362,7 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
 {
        struct page *page = NULL;
        spinlock_t *ptl;
+       pte_t pte;
 retry:
        ptl = pmd_lockptr(mm, pmd);
        spin_lock(ptl);
@@ -4371,12 +4372,13 @@ retry:
         */
        if (!pmd_huge(*pmd))
                goto out;
-       if (pmd_present(*pmd)) {
+       pte = huge_ptep_get((pte_t *)pmd);
+       if (pte_present(pte)) {
                page = pmd_page(*pmd) + ((address & ~PMD_MASK) >> PAGE_SHIFT);
                if (flags & FOLL_GET)
                        get_page(page);
        } else {
-               if (is_hugetlb_entry_migration(huge_ptep_get((pte_t *)pmd))) {
+               if (is_hugetlb_entry_migration(pte)) {
                        spin_unlock(ptl);
                        __migration_entry_wait(mm, (pte_t *)pmd, ptl);
                        goto retry;
index bc0a8d8..1ad20ad 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kmemleak.h>
+#include <linux/linkage.h>
 #include <linux/memblock.h>
 #include <linux/memory.h>
 #include <linux/mm.h>
@@ -60,6 +61,25 @@ void kasan_unpoison_shadow(const void *address, size_t size)
        }
 }
 
+static void __kasan_unpoison_stack(struct task_struct *task, void *sp)
+{
+       void *base = task_stack_page(task);
+       size_t size = sp - base;
+
+       kasan_unpoison_shadow(base, size);
+}
+
+/* Unpoison the entire stack for a task. */
+void kasan_unpoison_task_stack(struct task_struct *task)
+{
+       __kasan_unpoison_stack(task, task_stack_page(task) + THREAD_SIZE);
+}
+
+/* Unpoison the stack for the current task beyond a watermark sp value. */
+asmlinkage void kasan_unpoison_remaining_stack(void *sp)
+{
+       __kasan_unpoison_stack(current, sp);
+}
 
 /*
  * All functions below always inlined so compiler could
index 9174ec5..d56142b 100644 (file)
@@ -1493,7 +1493,6 @@ COMPAT_SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
 COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode, compat_ulong_t __user *, nmask,
                       compat_ulong_t, maxnode)
 {
-       long err = 0;
        unsigned long __user *nm = NULL;
        unsigned long nr_bits, alloc_size;
        DECLARE_BITMAP(bm, MAX_NUMNODES);
@@ -1502,14 +1501,13 @@ COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode, compat_ulong_t __user *, nmask,
        alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
 
        if (nmask) {
-               err = compat_get_bitmap(bm, nmask, nr_bits);
+               if (compat_get_bitmap(bm, nmask, nr_bits))
+                       return -EFAULT;
                nm = compat_alloc_user_space(alloc_size);
-               err |= copy_to_user(nm, bm, alloc_size);
+               if (copy_to_user(nm, bm, alloc_size))
+                       return -EFAULT;
        }
 
-       if (err)
-               return -EFAULT;
-
        return sys_set_mempolicy(mode, nm, nr_bits+1);
 }
 
@@ -1517,7 +1515,6 @@ COMPAT_SYSCALL_DEFINE6(mbind, compat_ulong_t, start, compat_ulong_t, len,
                       compat_ulong_t, mode, compat_ulong_t __user *, nmask,
                       compat_ulong_t, maxnode, compat_ulong_t, flags)
 {
-       long err = 0;
        unsigned long __user *nm = NULL;
        unsigned long nr_bits, alloc_size;
        nodemask_t bm;
@@ -1526,14 +1523,13 @@ COMPAT_SYSCALL_DEFINE6(mbind, compat_ulong_t, start, compat_ulong_t, len,
        alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
 
        if (nmask) {
-               err = compat_get_bitmap(nodes_addr(bm), nmask, nr_bits);
+               if (compat_get_bitmap(nodes_addr(bm), nmask, nr_bits))
+                       return -EFAULT;
                nm = compat_alloc_user_space(alloc_size);
-               err |= copy_to_user(nm, nodes_addr(bm), alloc_size);
+               if (copy_to_user(nm, nodes_addr(bm), alloc_size))
+                       return -EFAULT;
        }
 
-       if (err)
-               return -EFAULT;
-
        return sys_mbind(start, len, mode, nm, nr_bits+1, flags);
 }
 
index a089cca..ebc9d19 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
 #include <asm/tlb.h>
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_MSM_APP_SETTINGS
+#include <asm/app_api.h>
+#endif
+
 #include "internal.h"
 
 #ifndef arch_mmap_check
@@ -1297,6 +1301,11 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
        if (!len)
                return -EINVAL;
 
+#ifdef CONFIG_MSM_APP_SETTINGS
+       if (use_app_setting)
+               apply_app_setting_bit(file);
+#endif
+
        /*
         * Does the application expect PROT_READ to imply PROT_EXEC?
         *
index b8d927c..a6b2f21 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/kthread.h>
 #include <linux/net.h>
 #include <linux/nsproxy.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/socket.h>
 #include <linux/string.h>
@@ -478,11 +479,16 @@ static int ceph_tcp_connect(struct ceph_connection *con)
 {
        struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
        struct socket *sock;
+       unsigned int noio_flag;
        int ret;
 
        BUG_ON(con->sock);
+
+       /* sock_create_kern() allocates with GFP_KERNEL */
+       noio_flag = memalloc_noio_save();
        ret = sock_create_kern(read_pnet(&con->msgr->net), paddr->ss_family,
                               SOCK_STREAM, IPPROTO_TCP, &sock);
+       memalloc_noio_restore(noio_flag);
        if (ret)
                return ret;
        sock->sk->sk_allocation = GFP_NOFS;
index 3a2b21e..72e1e83 100644 (file)
@@ -154,17 +154,18 @@ void ping_hash(struct sock *sk)
 void ping_unhash(struct sock *sk)
 {
        struct inet_sock *isk = inet_sk(sk);
+
        pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
+       write_lock_bh(&ping_table.lock);
        if (sk_hashed(sk)) {
-               write_lock_bh(&ping_table.lock);
                hlist_nulls_del(&sk->sk_nulls_node);
                sk_nulls_node_init(&sk->sk_nulls_node);
                sock_put(sk);
                isk->inet_num = 0;
                isk->inet_sport = 0;
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
-               write_unlock_bh(&ping_table.lock);
        }
+       write_unlock_bh(&ping_table.lock);
 }
 EXPORT_SYMBOL_GPL(ping_unhash);
 
index 9af0f46..d162ce4 100644 (file)
@@ -792,6 +792,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf
        struct rtable *rt;
        struct flowi4 fl4;
        const struct iphdr *iph = (const struct iphdr *) skb->data;
+       struct net *net = dev_net(skb->dev);
        int oif = skb->dev->ifindex;
        u8 tos = RT_TOS(iph->tos);
        u8 prot = iph->protocol;
@@ -799,7 +800,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf
 
        rt = (struct rtable *) dst;
 
-       __build_flow_key(sock_net(sk), &fl4, sk, iph, oif, tos, prot, mark, 0);
+       __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0);
        __ip_do_redirect(rt, skb, &fl4, true);
 }
 
index add152e..31e172c 100644 (file)
@@ -2082,6 +2082,8 @@ static int ip6_route_del(struct fib6_config *cfg)
                                continue;
                        if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
                                continue;
+                       if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
+                               continue;
                        dst_hold(&rt->dst);
                        read_unlock_bh(&table->tb6_lock);
 
index 4f4c45b..25b5bac 100644 (file)
@@ -3397,6 +3397,27 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
                            !ether_addr_equal(bssid, hdr->addr1))
                                return false;
                }
+
+               /*
+                * 802.11-2016 Table 9-26 says that for data frames, A1 must be
+                * the BSSID - we've checked that already but may have accepted
+                * the wildcard (ff:ff:ff:ff:ff:ff).
+                *
+                * It also says:
+                *      The BSSID of the Data frame is determined as follows:
+                *      a) If the STA is contained within an AP or is associated
+                *         with an AP, the BSSID is the address currently in use
+                *         by the STA contained in the AP.
+                *
+                * So we should not accept data frames with an address that's
+                * multicast.
+                *
+                * Accepting it also opens a security problem because stations
+                * could encrypt it with the GTK and inject traffic that way.
+                */
+               if (ieee80211_is_data(hdr->frame_control) && multicast)
+                       return false;
+
                return true;
        case NL80211_IFTYPE_WDS:
                if (bssid || !ieee80211_is_data(hdr->frame_control))
index 3975ac8..d768001 100644 (file)
@@ -4138,8 +4138,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                if (unlikely(!PAGE_ALIGNED(req->tp_block_size)))
                        goto out;
                if (po->tp_version >= TPACKET_V3 &&
-                   (int)(req->tp_block_size -
-                         BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0)
+                   req->tp_block_size <=
+                         BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv))
                        goto out;
                if (unlikely(req->tp_frame_size < po->tp_hdrlen +
                                        po->tp_reserve))
index 138f2d6..5758818 100644 (file)
@@ -4422,6 +4422,12 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
        if (!asoc)
                return -EINVAL;
 
+       /* If there is a thread waiting on more sndbuf space for
+        * sending on this asoc, it cannot be peeled.
+        */
+       if (waitqueue_active(&asoc->wait))
+               return -EBUSY;
+
        /* An association cannot be branched off from an already peeled-off
         * socket, nor is this supported for tcp style sockets.
         */
@@ -6960,8 +6966,6 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                 */
                release_sock(sk);
                current_timeo = schedule_timeout(current_timeo);
-               if (sk != asoc->base.sk)
-                       goto do_error;
                lock_sock(sk);
 
                *timeo_p = current_timeo;
index 11a2967..876bb66 100644 (file)
@@ -533,7 +533,7 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
        return used;
 }
 
-int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
+static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        int err = simple_setattr(dentry, iattr);
 
index 06095cc..1f0687d 100644 (file)
@@ -541,9 +541,13 @@ gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
                return gss_new;
        gss_msg = gss_add_msg(gss_new);
        if (gss_msg == gss_new) {
-               int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg);
+               int res;
+               atomic_inc(&gss_msg->count);
+               res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg);
                if (res) {
                        gss_unhash_msg(gss_new);
+                       atomic_dec(&gss_msg->count);
+                       gss_release_msg(gss_new);
                        gss_msg = ERR_PTR(res);
                }
        } else
@@ -836,6 +840,7 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
                        warn_gssd();
                gss_release_msg(gss_msg);
        }
+       gss_release_msg(gss_msg);
 }
 
 static void gss_pipe_dentry_destroy(struct dentry *dir,
index 648f2a6..cb13815 100644 (file)
@@ -381,6 +381,10 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
        dev = dev_get_by_name(net, driver_name);
        if (!dev)
                return -ENODEV;
+       if (tipc_mtu_bad(dev, 0)) {
+               dev_put(dev);
+               return -EINVAL;
+       }
 
        /* Associate TIPC bearer with L2 bearer */
        rcu_assign_pointer(b->media_ptr, dev);
@@ -570,14 +574,19 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
        if (!b_ptr)
                return NOTIFY_DONE;
 
-       b_ptr->mtu = dev->mtu;
-
        switch (evt) {
        case NETDEV_CHANGE:
                if (netif_carrier_ok(dev))
                        break;
        case NETDEV_GOING_DOWN:
+               tipc_reset_bearer(net, b_ptr);
+               break;
        case NETDEV_CHANGEMTU:
+               if (tipc_mtu_bad(dev, 0)) {
+                       bearer_disable(net, b_ptr);
+                       break;
+               }
+               b_ptr->mtu = dev->mtu;
                tipc_reset_bearer(net, b_ptr);
                break;
        case NETDEV_CHANGEADDR:
index 552185b..5f11e18 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "netlink.h"
 #include "core.h"
+#include "msg.h"
 #include <net/genetlink.h>
 
 #define MAX_MEDIA      3
@@ -61,6 +62,9 @@
 #define TIPC_MEDIA_TYPE_IB     2
 #define TIPC_MEDIA_TYPE_UDP    3
 
+/* minimum bearer MTU */
+#define TIPC_MIN_BEARER_MTU    (MAX_H_SIZE + INT_H_SIZE)
+
 /**
  * struct tipc_node_map - set of node identifiers
  * @count: # of nodes in set
@@ -226,4 +230,13 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
 void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
                         struct sk_buff_head *xmitq);
 
+/* check if device MTU is too low for tipc headers */
+static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve)
+{
+       if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve)
+               return false;
+       netdev_warn(dev, "MTU too low for tipc bearer\n");
+       return true;
+}
+
 #endif /* _TIPC_BEARER_H */
index 03a8428..e2bdb07 100644 (file)
@@ -69,6 +69,7 @@ static int __net_init tipc_init_net(struct net *net)
        if (err)
                goto out_nametbl;
 
+       INIT_LIST_HEAD(&tn->dist_queue);
        err = tipc_topsrv_start(net);
        if (err)
                goto out_subscr;
index 18e95a8..fe3b89e 100644 (file)
@@ -103,6 +103,9 @@ struct tipc_net {
        spinlock_t nametbl_lock;
        struct name_table *nametbl;
 
+       /* Name dist queue */
+       struct list_head dist_queue;
+
        /* Topology subscription server */
        struct tipc_server *topsrv;
        atomic_t subscription_count;
index f51c8bd..c4c151b 100644 (file)
 
 int sysctl_tipc_named_timeout __read_mostly = 2000;
 
-/**
- * struct tipc_dist_queue - queue holding deferred name table updates
- */
-static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue);
-
 struct distr_queue_item {
        struct distr_item i;
        u32 dtype;
@@ -67,6 +62,8 @@ static void publ_to_item(struct distr_item *i, struct publication *p)
 
 /**
  * named_prepare_buf - allocate & initialize a publication message
+ *
+ * The buffer returned is of size INT_H_SIZE + payload size
  */
 static struct sk_buff *named_prepare_buf(struct net *net, u32 type, u32 size,
                                         u32 dest)
@@ -171,9 +168,9 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
        struct publication *publ;
        struct sk_buff *skb = NULL;
        struct distr_item *item = NULL;
-       uint msg_dsz = (tipc_node_get_mtu(net, dnode, 0) / ITEM_SIZE) *
-                       ITEM_SIZE;
-       uint msg_rem = msg_dsz;
+       u32 msg_dsz = ((tipc_node_get_mtu(net, dnode, 0) - INT_H_SIZE) /
+                       ITEM_SIZE) * ITEM_SIZE;
+       u32 msg_rem = msg_dsz;
 
        list_for_each_entry(publ, pls, local_list) {
                /* Prepare next buffer: */
@@ -340,9 +337,11 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
  * tipc_named_add_backlog - add a failed name table update to the backlog
  *
  */
-static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
+static void tipc_named_add_backlog(struct net *net, struct distr_item *i,
+                                  u32 type, u32 node)
 {
        struct distr_queue_item *e;
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
        unsigned long now = get_jiffies_64();
 
        e = kzalloc(sizeof(*e), GFP_ATOMIC);
@@ -352,7 +351,7 @@ static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
        e->node = node;
        e->expires = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
        memcpy(e, i, sizeof(*i));
-       list_add_tail(&e->next, &tipc_dist_queue);
+       list_add_tail(&e->next, &tn->dist_queue);
 }
 
 /**
@@ -362,10 +361,11 @@ static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
 void tipc_named_process_backlog(struct net *net)
 {
        struct distr_queue_item *e, *tmp;
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
        char addr[16];
        unsigned long now = get_jiffies_64();
 
-       list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
+       list_for_each_entry_safe(e, tmp, &tn->dist_queue, next) {
                if (time_after(e->expires, now)) {
                        if (!tipc_update_nametbl(net, &e->i, e->node, e->dtype))
                                continue;
@@ -405,7 +405,7 @@ void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq)
                node = msg_orignode(msg);
                while (count--) {
                        if (!tipc_update_nametbl(net, item, node, mtype))
-                               tipc_named_add_backlog(item, mtype, node);
+                               tipc_named_add_backlog(net, item, mtype, node);
                        item++;
                }
                kfree_skb(skb);
index 3926b56..2df0b98 100644 (file)
@@ -102,9 +102,10 @@ static unsigned int tipc_hashfn(u32 addr)
 
 static void tipc_node_kref_release(struct kref *kref)
 {
-       struct tipc_node *node = container_of(kref, struct tipc_node, kref);
+       struct tipc_node *n = container_of(kref, struct tipc_node, kref);
 
-       tipc_node_delete(node);
+       kfree(n->bc_entry.link);
+       kfree_rcu(n, rcu);
 }
 
 void tipc_node_put(struct tipc_node *node)
@@ -216,21 +217,20 @@ static void tipc_node_delete(struct tipc_node *node)
 {
        list_del_rcu(&node->list);
        hlist_del_rcu(&node->hash);
-       kfree(node->bc_entry.link);
-       kfree_rcu(node, rcu);
+       tipc_node_put(node);
+
+       del_timer_sync(&node->timer);
+       tipc_node_put(node);
 }
 
 void tipc_node_stop(struct net *net)
 {
-       struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct tipc_net *tn = tipc_net(net);
        struct tipc_node *node, *t_node;
 
        spin_lock_bh(&tn->node_list_lock);
-       list_for_each_entry_safe(node, t_node, &tn->node_list, list) {
-               if (del_timer(&node->timer))
-                       tipc_node_put(node);
-               tipc_node_put(node);
-       }
+       list_for_each_entry_safe(node, t_node, &tn->node_list, list)
+               tipc_node_delete(node);
        spin_unlock_bh(&tn->node_list_lock);
 }
 
@@ -313,9 +313,7 @@ static void tipc_node_timeout(unsigned long data)
                if (rc & TIPC_LINK_DOWN_EVT)
                        tipc_node_link_down(n, bearer_id, false);
        }
-       if (!mod_timer(&n->timer, jiffies + n->keepalive_intv))
-               tipc_node_get(n);
-       tipc_node_put(n);
+       mod_timer(&n->timer, jiffies + n->keepalive_intv);
 }
 
 /**
@@ -730,7 +728,7 @@ static void tipc_node_fsm_evt(struct tipc_node *n, int evt)
                        state = SELF_UP_PEER_UP;
                        break;
                case SELF_LOST_CONTACT_EVT:
-                       state = SELF_DOWN_PEER_LEAVING;
+                       state = SELF_DOWN_PEER_DOWN;
                        break;
                case SELF_ESTABL_CONTACT_EVT:
                case PEER_LOST_CONTACT_EVT:
@@ -749,7 +747,7 @@ static void tipc_node_fsm_evt(struct tipc_node *n, int evt)
                        state = SELF_UP_PEER_UP;
                        break;
                case PEER_LOST_CONTACT_EVT:
-                       state = SELF_LEAVING_PEER_DOWN;
+                       state = SELF_DOWN_PEER_DOWN;
                        break;
                case SELF_LOST_CONTACT_EVT:
                case PEER_ESTABL_CONTACT_EVT:
index b26b7a1..65171f8 100644 (file)
@@ -777,9 +777,11 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
  * @tsk: receiving socket
  * @skb: pointer to message buffer.
  */
-static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb)
+static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
+                             struct sk_buff_head *xmitq)
 {
        struct sock *sk = &tsk->sk;
+       u32 onode = tsk_own_node(tsk);
        struct tipc_msg *hdr = buf_msg(skb);
        int mtyp = msg_type(hdr);
        int conn_cong;
@@ -792,7 +794,8 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb)
 
        if (mtyp == CONN_PROBE) {
                msg_set_type(hdr, CONN_PROBE_REPLY);
-               tipc_sk_respond(sk, skb, TIPC_OK);
+               if (tipc_msg_reverse(onode, &skb, TIPC_OK))
+                       __skb_queue_tail(xmitq, skb);
                return;
        } else if (mtyp == CONN_ACK) {
                conn_cong = tsk_conn_cong(tsk);
@@ -1647,7 +1650,8 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)
  *
  * Returns true if message was added to socket receive queue, otherwise false
  */
-static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
+static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
+                      struct sk_buff_head *xmitq)
 {
        struct socket *sock = sk->sk_socket;
        struct tipc_sock *tsk = tipc_sk(sk);
@@ -1657,7 +1661,7 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
        int usr = msg_user(hdr);
 
        if (unlikely(msg_user(hdr) == CONN_MANAGER)) {
-               tipc_sk_proto_rcv(tsk, skb);
+               tipc_sk_proto_rcv(tsk, skb, xmitq);
                return false;
        }
 
@@ -1700,7 +1704,8 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
        return true;
 
 reject:
-       tipc_sk_respond(sk, skb, err);
+       if (tipc_msg_reverse(tsk_own_node(tsk), &skb, err))
+               __skb_queue_tail(xmitq, skb);
        return false;
 }
 
@@ -1716,9 +1721,24 @@ reject:
 static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
        unsigned int truesize = skb->truesize;
+       struct sk_buff_head xmitq;
+       u32 dnode, selector;
 
-       if (likely(filter_rcv(sk, skb)))
+       __skb_queue_head_init(&xmitq);
+
+       if (likely(filter_rcv(sk, skb, &xmitq))) {
                atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt);
+               return 0;
+       }
+
+       if (skb_queue_empty(&xmitq))
+               return 0;
+
+       /* Send response/rejected message */
+       skb = __skb_dequeue(&xmitq);
+       dnode = msg_destnode(buf_msg(skb));
+       selector = msg_origport(buf_msg(skb));
+       tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);
        return 0;
 }
 
@@ -1732,12 +1752,13 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
  * Caller must hold socket lock
  */
 static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
-                           u32 dport)
+                           u32 dport, struct sk_buff_head *xmitq)
 {
+       unsigned long time_limit = jiffies + 2;
+       struct sk_buff *skb;
        unsigned int lim;
        atomic_t *dcnt;
-       struct sk_buff *skb;
-       unsigned long time_limit = jiffies + 2;
+       u32 onode;
 
        while (skb_queue_len(inputq)) {
                if (unlikely(time_after_eq(jiffies, time_limit)))
@@ -1749,20 +1770,22 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
 
                /* Add message directly to receive queue if possible */
                if (!sock_owned_by_user(sk)) {
-                       filter_rcv(sk, skb);
+                       filter_rcv(sk, skb, xmitq);
                        continue;
                }
 
                /* Try backlog, compensating for double-counted bytes */
                dcnt = &tipc_sk(sk)->dupl_rcvcnt;
-               if (sk->sk_backlog.len)
+               if (!sk->sk_backlog.len)
                        atomic_set(dcnt, 0);
                lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
                if (likely(!sk_add_backlog(sk, skb, lim)))
                        continue;
 
                /* Overload => reject message back to sender */
-               tipc_sk_respond(sk, skb, TIPC_ERR_OVERLOAD);
+               onode = tipc_own_addr(sock_net(sk));
+               if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD))
+                       __skb_queue_tail(xmitq, skb);
                break;
        }
 }
@@ -1775,12 +1798,14 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
  */
 void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
 {
+       struct sk_buff_head xmitq;
        u32 dnode, dport = 0;
        int err;
        struct tipc_sock *tsk;
        struct sock *sk;
        struct sk_buff *skb;
 
+       __skb_queue_head_init(&xmitq);
        while (skb_queue_len(inputq)) {
                dport = tipc_skb_peek_port(inputq, dport);
                tsk = tipc_sk_lookup(net, dport);
@@ -1788,9 +1813,14 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
                if (likely(tsk)) {
                        sk = &tsk->sk;
                        if (likely(spin_trylock_bh(&sk->sk_lock.slock))) {
-                               tipc_sk_enqueue(inputq, sk, dport);
+                               tipc_sk_enqueue(inputq, sk, dport, &xmitq);
                                spin_unlock_bh(&sk->sk_lock.slock);
                        }
+                       /* Send pending response/rejected messages, if any */
+                       while ((skb = __skb_dequeue(&xmitq))) {
+                               dnode = msg_destnode(buf_msg(skb));
+                               tipc_node_xmit_skb(net, skb, dnode, dport);
+                       }
                        sock_put(sk);
                        continue;
                }
index 6af78c6..78d6b78 100644 (file)
@@ -52,7 +52,7 @@
 /* IANA assigned UDP port */
 #define UDP_PORT_DEFAULT       6118
 
-#define UDP_MIN_HEADROOM        28
+#define UDP_MIN_HEADROOM        48
 
 static const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {
        [TIPC_NLA_UDP_UNSPEC]   = {.type = NLA_UNSPEC},
@@ -376,6 +376,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
                udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
                udp_conf.use_udp_checksums = false;
                ub->ifindex = dev->ifindex;
+               if (tipc_mtu_bad(dev, sizeof(struct iphdr) +
+                                     sizeof(struct udphdr))) {
+                       err = -EINVAL;
+                       goto err;
+               }
                b->mtu = dev->mtu - sizeof(struct iphdr)
                        - sizeof(struct udphdr);
 #if IS_ENABLED(CONFIG_IPV6)
index 0a369bb..662bdd2 100644 (file)
@@ -842,7 +842,7 @@ static void vmci_transport_peer_detach_cb(u32 sub_id,
         * qp_handle.
         */
        if (vmci_handle_is_invalid(e_payload->handle) ||
-           vmci_handle_is_equal(trans->qp_handle, e_payload->handle))
+           !vmci_handle_is_equal(trans->qp_handle, e_payload->handle))
                return;
 
        /* We don't ask for delayed CBs when we subscribe to this event (we
@@ -2154,7 +2154,7 @@ module_exit(vmci_transport_exit);
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMCI transport for Virtual Sockets");
-MODULE_VERSION("1.0.2.0-k");
+MODULE_VERSION("1.0.3.0-k");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("vmware_vsock");
 MODULE_ALIAS_NETPROTO(PF_VSOCK);
index 5cfe6fd..be5ab8c 100644 (file)
@@ -208,16 +208,7 @@ struct cfg80211_event {
        enum cfg80211_event_type type;
 
        union {
-               struct {
-                       u8 bssid[ETH_ALEN];
-                       const u8 *req_ie;
-                       const u8 *resp_ie;
-                       size_t req_ie_len;
-                       size_t resp_ie_len;
-                       struct cfg80211_bss *bss;
-                       int status; /* -1 = failed; 0..65535 = status code */
-                       enum nl80211_timeout_reason timeout_reason;
-               } cr;
+               struct cfg80211_connect_resp_params cr;
                struct {
                        const u8 *req_ie;
                        const u8 *resp_ie;
@@ -373,12 +364,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
                     struct cfg80211_connect_params *connect,
                     struct cfg80211_cached_keys *connkeys,
                     const u8 *prev_bssid);
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
-                              const u8 *req_ie, size_t req_ie_len,
-                              const u8 *resp_ie, size_t resp_ie_len,
-                              int status, bool wextev,
-                              struct cfg80211_bss *bss,
-                              enum nl80211_timeout_reason timeout_reason);
+void __cfg80211_connect_result(struct net_device *dev,
+                              struct cfg80211_connect_resp_params *params,
+                              bool wextev);
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                             size_t ie_len, u16 reason, bool from_ap);
 int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
index a71f880..44cb3dc 100644 (file)
@@ -59,6 +59,8 @@ country AR:
        (5490 - 5590 @ 80), (36)
        (5650 - 5730 @ 80), (36)
        (5735 - 5835 @ 80), (36)
+       # 60 gHz band channels 1-3
+       (57240 - 63720 @ 2160), (40), NO-OUTDOOR
 
 country AS: DFS-FCC
        (2402 - 2472 @ 40), (30)
@@ -92,6 +94,9 @@ country AU: DFS-FCC
        (5650 - 5730 @ 80), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (43), NO-OUTDOOR
+
 country AW: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -108,8 +113,6 @@ country BA: DFS-ETSI
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
        (5490 - 5710 @ 160), (30), DFS
-       # 60 gHz band channels 1-4, ref: Etsi En 302 567
-       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
 
 country BB: DFS-FCC
        (2402 - 2482 @ 40), (20)
@@ -136,7 +139,7 @@ country BE: DFS-ETSI
        (5900 - 5920 @ 10), (30)
        (5910 - 5930 @ 10), (30)
        # 60 gHz band channels 1-4, ref: Etsi En 302 567
-       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+       (57240 - 65880 @ 2160), (40)
 
 country BF: DFS-FCC
        (2402 - 2482 @ 40), (20)
@@ -191,6 +194,9 @@ country BO: DFS-ETSI
        (5250 - 5330 @ 80), (30), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country BR: DFS-FCC
        (2402 - 2482 @ 40), (30)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -198,6 +204,9 @@ country BR: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3
+       (57240 - 63720 @ 2160), (40)
+
 country BS: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -231,6 +240,9 @@ country CA: DFS-FCC
        (5650 - 5730 @ 80), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3
+       (57240 - 63720 @ 2160), (40)
+
 country CF: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 40), (24)
@@ -253,6 +265,9 @@ country CH: DFS-ETSI
        (5900 - 5920 @ 10), (30)
        (5910 - 5930 @ 10), (30)
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country CI: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -265,16 +280,16 @@ country CL:
        (5170 - 5330 @ 160), (20)
        (5735 - 5835 @ 80), (20)
 
+       # 60 gHz band channels 1-3
+       (57240 - 63720 @ 2160), (50), NO-OUTDOOR
+
 country CN: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
        (5735 - 5835 @ 80), (33)
-       # 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
-       # ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
-       (57240 - 59400 @ 2160), (28)
+       # 60 gHz band channels 2,3: 44dBm
        (59400 - 63720 @ 2160), (44)
-       (63720 - 65880 @ 2160), (28)
 
 country CO: DFS-FCC
        (2402 - 2482 @ 40), (20)
@@ -290,6 +305,9 @@ country CR: DFS-FCC
        (5490 - 5730 @ 20), (24), DFS
        (5735 - 5835 @ 20), (30)
 
+       # 60 gHz band channels 1-3
+       (57240 - 63720 @ 2160), (30)
+
 country CX: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -398,6 +416,9 @@ country EC: DFS-FCC
        (5490 - 5730 @ 20), (24), DFS
        (5735 - 5835 @ 20), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country EE: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -512,8 +533,6 @@ country GE: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (18), AUTO-BW
        (5250 - 5330 @ 80), (18), DFS, AUTO-BW
-       # 60 gHz band channels 1-4, ref: Etsi En 302 567
-       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
 
 country GF: DFS-ETSI
        (2402 - 2482 @ 40), (20)
@@ -570,6 +589,9 @@ country GU: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country GY:
        (2402 - 2482 @ 40), (30)
        (5735 - 5835 @ 80), (30)
@@ -581,12 +603,18 @@ country HK: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4, ref: FCC/EU
+       (57240 - 65880 @ 2160), (40)
+
 country HN:
        (2402 - 2482 @ 40), (20)
        (5170 - 5330 @ 160), (24)
        (5490 - 5730 @ 160), (24)
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country HR: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -638,7 +666,6 @@ country IE: DFS-ETSI
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
        (5490 - 5710 @ 160), (30), DFS
-       # 60 gHz band channels 1-4, ref: Etsi En 302 567
        # 5.9ghz band
        # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf
        (5850 - 5870 @ 10), (30)
@@ -648,7 +675,7 @@ country IE: DFS-ETSI
        (5890 - 5910 @ 10), (30)
        (5900 - 5920 @ 10), (30)
        (5910 - 5930 @ 10), (30)
-        # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
        (57240 - 65880 @ 2160), (40), NO-OUTDOOR
 
 country IL: DFS-ETSI
@@ -656,6 +683,9 @@ country IL: DFS-ETSI
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
 
+       # 60 gHz band channels 1-4, base on Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country IN:
        (2402 - 2482 @ 40), (20)
        (5170 - 5330 @ 160), (23)
@@ -706,20 +736,25 @@ country JM: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country JO:
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23)
        (5735 - 5835 @ 80), (23)
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country JP: DFS-JP
        (2402 - 2482 @ 40), (20)
        (2474 - 2494 @ 20), (20), NO-OFDM
        (5170 - 5250 @ 80), (20), AUTO-BW, NO-OUTDOOR
        (5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR
        (5490 - 5710 @ 160), (20), DFS
-       # 60 GHz band channels 2-4 at 10mW,
-       # ref: http://www.arib.or.jp/english/html/overview/doc/1-STD-T74v1_1.pdf
-       (59000 - 66000 @ 2160), (10 mW)
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (40)
 
 country KE: DFS-ETSI
        (2402 - 2482 @ 40), (20)
@@ -748,7 +783,7 @@ country KR: DFS-ETSI
        (5735 - 5835 @ 80), (30)
        # 60 GHz band channels 1-4,
        # ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99
-       (57000 - 66000 @ 2160), (43)
+       (57240 - 65880 @ 2160), (43)
 
 country KP: DFS-ETSI
        (2402 - 2482 @ 40), (20)
@@ -801,6 +836,9 @@ country LI: DFS-ETSI
        (5900 - 5920 @ 10), (30)
        (5910 - 5930 @ 10), (30)
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country LK: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 20), (24)
@@ -862,6 +900,7 @@ country LV: DFS-ETSI
        (5890 - 5910 @ 10), (30)
        (5900 - 5920 @ 10), (30)
        (5910 - 5930 @ 10), (30)
+
        # 60 gHz band channels 1-4, ref: Etsi En 302 567
        (57240 - 65880 @ 2160), (40), NO-OUTDOOR
 
@@ -870,6 +909,9 @@ country MA: DFS-ETSI
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country MC: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -906,8 +948,6 @@ country MK: DFS-ETSI
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
        (5490 - 5710 @ 160), (30), DFS
-       # 60 gHz band channels 1-4, ref: Etsi En 302 567
-       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
 
 country MN: DFS-FCC
        (2402 - 2482 @ 40), (20)
@@ -985,6 +1025,9 @@ country MX: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country MY: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -992,6 +1035,9 @@ country MY: DFS-FCC
        (5490 - 5650 @ 160), (24), DFS
        (5735 - 5815 @ 80), (24)
 
+       # 60 gHz band channels 1-3
+       (57240 - 63720 @ 2160), (40)
+
 country NA: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -1011,6 +1057,9 @@ country NI: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country NL: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -1057,6 +1106,9 @@ country NZ: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country OM: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -1096,6 +1148,9 @@ country PH: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country PK:
        (2402 - 2482 @ 40), (30)
        (5735 - 5835 @ 80), (30)
@@ -1168,6 +1223,9 @@ country PY: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country QA:
        (2402 - 2482 @ 40), (20)
        (5735 - 5835 @ 80), (30)
@@ -1211,6 +1269,9 @@ country RU:
        (5490 - 5730 @ 160), (30)
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (40)
+
 country RW: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -1248,6 +1309,9 @@ country SG: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4, ref: Etsi En 302 567
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country SI: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -1329,6 +1393,9 @@ country TH: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (40)
+
 country TN: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -1339,8 +1406,6 @@ country TR: DFS-ETSI
        (5170 - 5250 @ 80), (23), AUTO-BW
        (5250 - 5330 @ 80), (23), DFS, AUTO-BW
        (5490 - 5710 @ 160), (30), DFS
-       # 60 gHz band channels 1-4, ref: Etsi En 302 567
-       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
 
 country TT:
        (2402 - 2482 @ 40), (20)
@@ -1348,6 +1413,9 @@ country TT:
        (5490 - 5730 @ 160), (36)
        (5735 - 5835 @ 80), (36)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country TW: DFS-FCC
        (2402 - 2472 @ 40), (30)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -1355,6 +1423,9 @@ country TW: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-3, FCC
+       (57240 - 63720 @ 2160), (40)
+
 country TZ:
        (2402 - 2482 @ 40), (20)
        (5735 - 5835 @ 80), (30)
@@ -1373,7 +1444,7 @@ country UA: DFS-ETSI
        (5490 - 5670 @ 160), (20), DFS
        (5735 - 5835 @ 80), (20)
        # 60 gHz band channels 1-4, ref: Etsi En 302 567
-       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+       (57240 - 65880 @ 2160), (20)
 
 country UG: DFS-FCC
        (2402 - 2482 @ 40), (20)
@@ -1402,8 +1473,8 @@ country US: DFS-FCC
        (5910 - 5930 @ 10), (30)
        # 60g band
        # reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
-       # channels 1,2,3, EIRP=40dBm(43dBm peak)
-       (57240 - 63720 @ 2160), (40)
+       # channels 1,2,3,4,5,6 EIRP=40dBm(43dBm peak)
+       (57240 - 70200 @ 2160), (40)
 
 country UY: DFS-FCC
        (2402 - 2482 @ 40), (20)
@@ -1411,6 +1482,9 @@ country UY: DFS-FCC
         (5250 - 5330 @ 80), (23), DFS, AUTO-BW
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (40)
+
 country UZ: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
@@ -1442,6 +1516,9 @@ country VN: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (40)
+
 country VU: DFS-FCC
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (24), AUTO-BW
@@ -1467,7 +1544,6 @@ country XA: DFS-JP
        (5170 - 5250 @ 80), (20), NO-IR, AUTO-BW, NO-OUTDOOR
        (5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR
        (5490 - 5710 @ 160), (20), DFS
-       (59000 - 66000 @ 2160), (10 mW)
 
 country YE:
        (2402 - 2482 @ 40), (20)
@@ -1485,6 +1561,9 @@ country ZA: DFS-FCC
        (5490 - 5730 @ 160), (24), DFS
        (5735 - 5835 @ 80), (30)
 
+       # 60 gHz band channels 1-4
+       (57240 - 65880 @ 2160), (40), NO-OUTDOOR
+
 country ZW: DFS-ETSI
        (2402 - 2482 @ 40), (20)
        (5170 - 5250 @ 80), (23), AUTO-BW
index e2b1333..2bc6eaa 100644 (file)
@@ -26,9 +26,16 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
-       u8 *ie = mgmt->u.assoc_resp.variable;
-       int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
-       u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+       struct cfg80211_connect_resp_params cr;
+
+       memset(&cr, 0, sizeof(cr));
+       cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
+       cr.bssid = mgmt->bssid;
+       cr.bss = bss;
+       cr.resp_ie = mgmt->u.assoc_resp.variable;
+       cr.resp_ie_len =
+               len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+       cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
 
        trace_cfg80211_send_rx_assoc(dev, bss);
 
@@ -38,7 +45,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
         * and got a reject -- we only try again with an assoc
         * frame instead of reassoc.
         */
-       if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
+       if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
                cfg80211_unhold_bss(bss_from_pub(bss));
                cfg80211_put_bss(wiphy, bss);
                return;
@@ -46,10 +53,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
 
        nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues);
        /* update current_bss etc., consumes the bss reference */
-       __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
-                                 status_code,
-                                 status_code == WLAN_STATUS_SUCCESS, bss,
-                                 NL80211_TIMEOUT_UNSPECIFIED);
+       __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
 }
 EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
 
index 074cf0d..d0d09c2 100644 (file)
@@ -408,7 +408,19 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
                .len = sizeof(struct nl80211_bss_select_rssi_adjust)
        },
+       [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
+                                   .len = FILS_MAX_KEK_LEN },
+       [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
        [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
+       [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
+                                            .len = FILS_ERP_MAX_USERNAME_LEN },
+       [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
+                                         .len = FILS_ERP_MAX_REALM_LEN },
+       [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
+       [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
+                                       .len = FILS_ERP_MAX_RRK_LEN },
+       [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
+       [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
 };
 
 /* policy for the key attributes */
@@ -3653,6 +3665,19 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
                        return false;
                return true;
        case NL80211_CMD_CONNECT:
+               /* SAE not supported yet */
+               if (auth_type == NL80211_AUTHTYPE_SAE)
+                       return false;
+               /* FILS with SK PFS or PK not supported yet */
+               if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+                   auth_type == NL80211_AUTHTYPE_FILS_PK)
+                       return false;
+               if (!wiphy_ext_feature_isset(
+                           &rdev->wiphy,
+                           NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+                   auth_type == NL80211_AUTHTYPE_FILS_SK)
+                       return false;
+               return true;
        case NL80211_CMD_START_AP:
                /* SAE not supported yet */
                if (auth_type == NL80211_AUTHTYPE_SAE)
@@ -7780,6 +7805,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                req.flags |= ASSOC_REQ_USE_RRM;
        }
 
+       if (info->attrs[NL80211_ATTR_FILS_KEK]) {
+               req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
+               req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
+               if (!info->attrs[NL80211_ATTR_FILS_NONCES])
+                       return -EINVAL;
+               req.fils_nonces =
+                       nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
+       }
+
        err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
        if (!err) {
                wdev_lock(dev->ieee80211_ptr);
@@ -8499,6 +8533,35 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       if (wiphy_ext_feature_isset(&rdev->wiphy,
+                                   NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+           info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
+           info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
+           info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
+           info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+               connect.fils_erp_username =
+                       nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+               connect.fils_erp_username_len =
+                       nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+               connect.fils_erp_realm =
+                       nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+               connect.fils_erp_realm_len =
+                       nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+               connect.fils_erp_next_seq_num =
+                       nla_get_u16(
+                          info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
+               connect.fils_erp_rrk =
+                       nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+               connect.fils_erp_rrk_len =
+                       nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+       } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
+                  info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
+                  info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
+                  info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+               kzfree(connkeys);
+               return -EINVAL;
+       }
+
        wdev_lock(dev->ieee80211_ptr);
        err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
        wdev_unlock(dev->ieee80211_ptr);
@@ -8604,14 +8667,28 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
 
        memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
 
-       if (!info->attrs[NL80211_ATTR_MAC])
-               return -EINVAL;
-
        if (!info->attrs[NL80211_ATTR_PMKID])
                return -EINVAL;
 
        pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
-       pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       if (info->attrs[NL80211_ATTR_MAC]) {
+               pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       } else if (info->attrs[NL80211_ATTR_SSID] &&
+                  info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
+                  (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
+                   info->attrs[NL80211_ATTR_PMK])) {
+               pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+               pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+               pmksa.cache_id =
+                       nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
+       } else {
+               return -EINVAL;
+       }
+       if (info->attrs[NL80211_ATTR_PMK]) {
+               pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+               pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
+       }
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
@@ -12120,7 +12197,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + len, gfp);
        if (!msg)
                return;
 
@@ -12264,17 +12341,16 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
 }
 
 void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
-                                struct net_device *netdev, const u8 *bssid,
-                                const u8 *req_ie, size_t req_ie_len,
-                                const u8 *resp_ie, size_t resp_ie_len,
-                                int status,
-                                enum nl80211_timeout_reason timeout_reason,
+                                struct net_device *netdev,
+                                struct cfg80211_connect_resp_params *cr,
                                 gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
+                       cr->fils_kek_len + cr->pmk_len +
+                       (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
        if (!msg)
                return;
 
@@ -12286,17 +12362,31 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
            nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
-           (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
+           (cr->bssid &&
+            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
            nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
-                       status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
-                       status) ||
-           (status < 0 &&
+                       cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
+                       cr->status) ||
+           (cr->status < 0 &&
             (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
-             nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
-           (req_ie &&
-            nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
-           (resp_ie &&
-            nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+             nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
+                         cr->timeout_reason))) ||
+           (cr->req_ie &&
+            nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
+           (cr->resp_ie &&
+            nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
+                    cr->resp_ie)) ||
+           (cr->update_erp_next_seq_num &&
+            nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+                        cr->fils_erp_next_seq_num)) ||
+           (cr->status == WLAN_STATUS_SUCCESS &&
+            ((cr->fils_kek &&
+              nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
+                      cr->fils_kek)) ||
+             (cr->pmk &&
+              nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
+             (cr->pmkid &&
+              nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
@@ -12319,7 +12409,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
        if (!msg)
                return;
 
@@ -12357,7 +12447,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
        if (!msg)
                return;
 
@@ -12434,7 +12524,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
 
        trace_cfg80211_notify_new_peer_candidate(dev, addr);
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + ie_len, gfp);
        if (!msg)
                return;
 
@@ -12803,7 +12893,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + len, gfp);
        if (!msg)
                return -ENOMEM;
 
@@ -12846,7 +12936,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
        trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + len, gfp);
        if (!msg)
                return;
 
@@ -13650,7 +13740,7 @@ void cfg80211_ft_event(struct net_device *netdev,
        if (!ft_event->target_ap)
                return;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
        if (!msg)
                return;
 
index a749c9b..79e9270 100644 (file)
@@ -52,11 +52,8 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
                                struct net_device *netdev,
                                const u8 *addr, gfp_t gfp);
 void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
-                                struct net_device *netdev, const u8 *bssid,
-                                const u8 *req_ie, size_t req_ie_len,
-                                const u8 *resp_ie, size_t resp_ie_len,
-                                int status,
-                                enum nl80211_timeout_reason timeout_reason,
+                                struct net_device *netdev,
+                                struct cfg80211_connect_resp_params *params,
                                 gfp_t gfp);
 void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
                         struct net_device *netdev, const u8 *bssid,
index fe8a906..85c12c7 100644 (file)
@@ -276,10 +276,13 @@ void cfg80211_conn_work(struct work_struct *work)
                }
                treason = NL80211_TIMEOUT_UNSPECIFIED;
                if (cfg80211_conn_do_work(wdev, &treason)) {
-                       __cfg80211_connect_result(
-                                       wdev->netdev, bssid,
-                                       NULL, 0, NULL, 0, -1, false, NULL,
-                                       treason);
+                       struct cfg80211_connect_resp_params cr;
+
+                       memset(&cr, 0, sizeof(cr));
+                       cr.status = -1;
+                       cr.bssid = bssid;
+                       cr.timeout_reason = treason;
+                       __cfg80211_connect_result(wdev->netdev, &cr, false);
                }
                wdev_unlock(wdev);
        }
@@ -382,10 +385,13 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
                wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
                schedule_work(&rdev->conn_work);
        } else if (status_code != WLAN_STATUS_SUCCESS) {
-               __cfg80211_connect_result(wdev->netdev, mgmt->bssid,
-                                         NULL, 0, NULL, 0,
-                                         status_code, false, NULL,
-                                         NL80211_TIMEOUT_UNSPECIFIED);
+               struct cfg80211_connect_resp_params cr;
+
+               memset(&cr, 0, sizeof(cr));
+               cr.status = status_code;
+               cr.bssid = mgmt->bssid;
+               cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
+               __cfg80211_connect_result(wdev->netdev, &cr, false);
        } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
                wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
                schedule_work(&rdev->conn_work);
@@ -683,12 +689,9 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
  */
 
 /* This method must consume bss one way or another */
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
-                              const u8 *req_ie, size_t req_ie_len,
-                              const u8 *resp_ie, size_t resp_ie_len,
-                              int status, bool wextev,
-                              struct cfg80211_bss *bss,
-                              enum nl80211_timeout_reason timeout_reason)
+void __cfg80211_connect_result(struct net_device *dev,
+                              struct cfg80211_connect_resp_params *cr,
+                              bool wextev)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const u8 *country_ie;
@@ -700,48 +703,48 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
                    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
-               cfg80211_put_bss(wdev->wiphy, bss);
+               cfg80211_put_bss(wdev->wiphy, cr->bss);
                return;
        }
 
-       nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
-                                   bssid, req_ie, req_ie_len,
-                                   resp_ie, resp_ie_len,
-                                   status, timeout_reason, GFP_KERNEL);
+       nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
+                                   GFP_KERNEL);
 
 #ifdef CONFIG_CFG80211_WEXT
        if (wextev) {
-               if (req_ie && status == WLAN_STATUS_SUCCESS) {
+               if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) {
                        memset(&wrqu, 0, sizeof(wrqu));
-                       wrqu.data.length = req_ie_len;
-                       wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
+                       wrqu.data.length = cr->req_ie_len;
+                       wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
+                                           cr->req_ie);
                }
 
-               if (resp_ie && status == WLAN_STATUS_SUCCESS) {
+               if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) {
                        memset(&wrqu, 0, sizeof(wrqu));
-                       wrqu.data.length = resp_ie_len;
-                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
+                       wrqu.data.length = cr->resp_ie_len;
+                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
+                                           cr->resp_ie);
                }
 
                memset(&wrqu, 0, sizeof(wrqu));
                wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-               if (bssid && status == WLAN_STATUS_SUCCESS) {
-                       memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
-                       memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
+               if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) {
+                       memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN);
+                       memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN);
                        wdev->wext.prev_bssid_valid = true;
                }
                wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
        }
 #endif
 
-       if (!bss && (status == WLAN_STATUS_SUCCESS)) {
+       if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
                WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
-               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-                                      wdev->ssid, wdev->ssid_len,
-                                      wdev->conn_bss_type,
-                                      IEEE80211_PRIVACY_ANY);
-               if (bss)
-                       cfg80211_hold_bss(bss_from_pub(bss));
+               cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
+                                          wdev->ssid, wdev->ssid_len,
+                                          wdev->conn_bss_type,
+                                          IEEE80211_PRIVACY_ANY);
+               if (cr->bss)
+                       cfg80211_hold_bss(bss_from_pub(cr->bss));
        }
 
        if (wdev->current_bss) {
@@ -750,27 +753,27 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                wdev->current_bss = NULL;
        }
 
-       if (status != WLAN_STATUS_SUCCESS) {
+       if (cr->status != WLAN_STATUS_SUCCESS) {
                kzfree(wdev->connect_keys);
                wdev->connect_keys = NULL;
                wdev->ssid_len = 0;
-               if (bss) {
-                       cfg80211_unhold_bss(bss_from_pub(bss));
-                       cfg80211_put_bss(wdev->wiphy, bss);
+               if (cr->bss) {
+                       cfg80211_unhold_bss(bss_from_pub(cr->bss));
+                       cfg80211_put_bss(wdev->wiphy, cr->bss);
                }
                cfg80211_sme_free(wdev);
                return;
        }
 
-       if (WARN_ON(!bss))
+       if (WARN_ON(!cr->bss))
                return;
 
-       wdev->current_bss = bss_from_pub(bss);
+       wdev->current_bss = bss_from_pub(cr->bss);
 
        cfg80211_upload_connect_keys(wdev);
 
        rcu_read_lock();
-       country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+       country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
        if (!country_ie) {
                rcu_read_unlock();
                return;
@@ -787,64 +790,95 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
         * - country_ie + 2, the start of the country ie data, and
         * - and country_ie[1] which is the IE length
         */
-       regulatory_hint_country_ie(wdev->wiphy, bss->channel->band,
+       regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
                                   country_ie + 2, country_ie[1]);
        kfree(country_ie);
 }
 
 /* Consumes bss object one way or another */
-void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
-                         struct cfg80211_bss *bss, const u8 *req_ie,
-                         size_t req_ie_len, const u8 *resp_ie,
-                         size_t resp_ie_len, int status, gfp_t gfp,
-                         enum nl80211_timeout_reason timeout_reason)
+void cfg80211_connect_done(struct net_device *dev,
+                          struct cfg80211_connect_resp_params *params,
+                          gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
+       u8 *next;
 
-       if (bss) {
+       if (params->bss) {
                /* Make sure the bss entry provided by the driver is valid. */
-               struct cfg80211_internal_bss *ibss = bss_from_pub(bss);
+               struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
 
                if (WARN_ON(list_empty(&ibss->list))) {
-                       cfg80211_put_bss(wdev->wiphy, bss);
+                       cfg80211_put_bss(wdev->wiphy, params->bss);
                        return;
                }
        }
 
-       ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+       ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) +
+                    params->req_ie_len + params->resp_ie_len +
+                    params->fils_kek_len + params->pmk_len +
+                    (params->pmkid ? WLAN_PMKID_LEN : 0), gfp);
        if (!ev) {
-               cfg80211_put_bss(wdev->wiphy, bss);
+               cfg80211_put_bss(wdev->wiphy, params->bss);
                return;
        }
 
        ev->type = EVENT_CONNECT_RESULT;
-       if (bssid)
-               memcpy(ev->cr.bssid, bssid, ETH_ALEN);
-       if (req_ie_len) {
-               ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
-               ev->cr.req_ie_len = req_ie_len;
-               memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
+       next = ((u8 *)ev) + sizeof(*ev);
+       if (params->bssid) {
+               ev->cr.bssid = next;
+               memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN);
+               next += ETH_ALEN;
        }
-       if (resp_ie_len) {
-               ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
-               ev->cr.resp_ie_len = resp_ie_len;
-               memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+       if (params->req_ie_len) {
+               ev->cr.req_ie = next;
+               ev->cr.req_ie_len = params->req_ie_len;
+               memcpy((void *)ev->cr.req_ie, params->req_ie,
+                      params->req_ie_len);
+               next += params->req_ie_len;
        }
-       if (bss)
-               cfg80211_hold_bss(bss_from_pub(bss));
-       ev->cr.bss = bss;
-       ev->cr.status = status;
-       ev->cr.timeout_reason = timeout_reason;
+       if (params->resp_ie_len) {
+               ev->cr.resp_ie = next;
+               ev->cr.resp_ie_len = params->resp_ie_len;
+               memcpy((void *)ev->cr.resp_ie, params->resp_ie,
+                      params->resp_ie_len);
+               next += params->resp_ie_len;
+       }
+       if (params->fils_kek_len) {
+               ev->cr.fils_kek = next;
+               ev->cr.fils_kek_len = params->fils_kek_len;
+               memcpy((void *)ev->cr.fils_kek, params->fils_kek,
+                      params->fils_kek_len);
+               next += params->fils_kek_len;
+       }
+       if (params->pmk_len) {
+               ev->cr.pmk = next;
+               ev->cr.pmk_len = params->pmk_len;
+               memcpy((void *)ev->cr.pmk, params->pmk, params->pmk_len);
+               next += params->pmk_len;
+       }
+       if (params->pmkid) {
+               ev->cr.pmkid = next;
+               memcpy((void *)ev->cr.pmkid, params->pmkid, WLAN_PMKID_LEN);
+               next += WLAN_PMKID_LEN;
+       }
+       ev->cr.update_erp_next_seq_num = params->update_erp_next_seq_num;
+       if (params->update_erp_next_seq_num)
+               ev->cr.fils_erp_next_seq_num = params->fils_erp_next_seq_num;
+       if (params->bss)
+               cfg80211_hold_bss(bss_from_pub(params->bss));
+       ev->cr.bss = params->bss;
+       ev->cr.status = params->status;
+       ev->cr.timeout_reason = params->timeout_reason;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
        list_add_tail(&ev->list, &wdev->event_list);
        spin_unlock_irqrestore(&wdev->event_lock, flags);
        queue_work(cfg80211_wq, &rdev->event_work);
 }
-EXPORT_SYMBOL(cfg80211_connect_bss);
+EXPORT_SYMBOL(cfg80211_connect_done);
 
 /* Consumes bss object one way or another */
 void __cfg80211_roamed(struct wireless_dev *wdev,
index 305370c..afdbc12 100644 (file)
@@ -858,7 +858,6 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
 {
        struct cfg80211_event *ev;
        unsigned long flags;
-       const u8 *bssid = NULL;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
        while (!list_empty(&wdev->event_list)) {
@@ -870,15 +869,10 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                wdev_lock(wdev);
                switch (ev->type) {
                case EVENT_CONNECT_RESULT:
-                       if (!is_zero_ether_addr(ev->cr.bssid))
-                               bssid = ev->cr.bssid;
                        __cfg80211_connect_result(
-                               wdev->netdev, bssid,
-                               ev->cr.req_ie, ev->cr.req_ie_len,
-                               ev->cr.resp_ie, ev->cr.resp_ie_len,
-                               ev->cr.status,
-                               ev->cr.status == WLAN_STATUS_SUCCESS,
-                               ev->cr.bss, ev->cr.timeout_reason);
+                               wdev->netdev,
+                               &ev->cr,
+                               ev->cr.status == WLAN_STATUS_SUCCESS);
                        break;
                case EVENT_ROAMED:
                        __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
index 1dcd4ed..c72bcb3 100755 (executable)
@@ -2500,6 +2500,7 @@ sub process {
 
 # Check for git id commit length and improperly formed commit descriptions
                if ($in_commit_log && !$commit_log_possible_stack_dump &&
+                   $line !~ /^This reverts commit [0-9a-f]{7,40}/ &&
                    ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||
                     ($line =~ /\b[0-9a-f]{12,40}\b/i &&
                      $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i &&
index addf060..9cb4fe4 100644 (file)
@@ -46,7 +46,7 @@ static unsigned long key_gc_flags;
  * immediately unlinked.
  */
 struct key_type key_type_dead = {
-       .name = "dead",
+       .name = ".dead",
 };
 
 /*
index 1c3872a..442e350 100644 (file)
@@ -271,7 +271,8 @@ error:
  * Create and join an anonymous session keyring or join a named session
  * keyring, creating it if necessary.  A named session keyring must have Search
  * permission for it to be joined.  Session keyrings without this permit will
- * be skipped over.
+ * be skipped over.  It is not permitted for userspace to create or join
+ * keyrings whose name begin with a dot.
  *
  * If successful, the ID of the joined session keyring will be returned.
  */
@@ -288,12 +289,16 @@ long keyctl_join_session_keyring(const char __user *_name)
                        ret = PTR_ERR(name);
                        goto error;
                }
+
+               ret = -EPERM;
+               if (name[0] == '.')
+                       goto error_name;
        }
 
        /* join the session */
        ret = join_session_keyring(name);
+error_name:
        kfree(name);
-
 error:
        return ret;
 }
@@ -1223,8 +1228,8 @@ error:
  * Read or set the default keyring in which request_key() will cache keys and
  * return the old setting.
  *
- * If a process keyring is specified then this will be created if it doesn't
- * yet exist.  The old setting will be returned if successful.
+ * If a thread or process keyring is specified then it will be created if it
+ * doesn't yet exist.  The old setting will be returned if successful.
  */
 long keyctl_set_reqkey_keyring(int reqkey_defl)
 {
@@ -1249,11 +1254,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
 
        case KEY_REQKEY_DEFL_PROCESS_KEYRING:
                ret = install_process_keyring_to_cred(new);
-               if (ret < 0) {
-                       if (ret != -EEXIST)
-                               goto error;
-                       ret = 0;
-               }
+               if (ret < 0)
+                       goto error;
                goto set;
 
        case KEY_REQKEY_DEFL_DEFAULT:
index e6d5017..4ed9091 100644 (file)
@@ -125,13 +125,18 @@ error:
 }
 
 /*
- * Install a fresh thread keyring directly to new credentials.  This keyring is
- * allowed to overrun the quota.
+ * Install a thread keyring to the given credentials struct if it didn't have
+ * one already.  This is allowed to overrun the quota.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
  */
 int install_thread_keyring_to_cred(struct cred *new)
 {
        struct key *keyring;
 
+       if (new->thread_keyring)
+               return 0;
+
        keyring = keyring_alloc("_tid", new->uid, new->gid, new,
                                KEY_POS_ALL | KEY_USR_VIEW,
                                KEY_ALLOC_QUOTA_OVERRUN, NULL);
@@ -143,7 +148,9 @@ int install_thread_keyring_to_cred(struct cred *new)
 }
 
 /*
- * Install a fresh thread keyring, discarding the old one.
+ * Install a thread keyring to the current task if it didn't have one already.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
  */
 static int install_thread_keyring(void)
 {
@@ -154,8 +161,6 @@ static int install_thread_keyring(void)
        if (!new)
                return -ENOMEM;
 
-       BUG_ON(new->thread_keyring);
-
        ret = install_thread_keyring_to_cred(new);
        if (ret < 0) {
                abort_creds(new);
@@ -166,17 +171,17 @@ static int install_thread_keyring(void)
 }
 
 /*
- * Install a process keyring directly to a credentials struct.
+ * Install a process keyring to the given credentials struct if it didn't have
+ * one already.  This is allowed to overrun the quota.
  *
- * Returns -EEXIST if there was already a process keyring, 0 if one installed,
- * and other value on any other error
+ * Return: 0 if a process keyring is now present; -errno on failure.
  */
 int install_process_keyring_to_cred(struct cred *new)
 {
        struct key *keyring;
 
        if (new->process_keyring)
-               return -EEXIST;
+               return 0;
 
        keyring = keyring_alloc("_pid", new->uid, new->gid, new,
                                KEY_POS_ALL | KEY_USR_VIEW,
@@ -189,11 +194,9 @@ int install_process_keyring_to_cred(struct cred *new)
 }
 
 /*
- * Make sure a process keyring is installed for the current process.  The
- * existing process keyring is not replaced.
+ * Install a process keyring to the current task if it didn't have one already.
  *
- * Returns 0 if there is a process keyring by the end of this function, some
- * error otherwise.
+ * Return: 0 if a process keyring is now present; -errno on failure.
  */
 static int install_process_keyring(void)
 {
@@ -207,14 +210,18 @@ static int install_process_keyring(void)
        ret = install_process_keyring_to_cred(new);
        if (ret < 0) {
                abort_creds(new);
-               return ret != -EEXIST ? ret : 0;
+               return ret;
        }
 
        return commit_creds(new);
 }
 
 /*
- * Install a session keyring directly to a credentials struct.
+ * Install the given keyring as the session keyring of the given credentials
+ * struct, replacing the existing one if any.  If the given keyring is NULL,
+ * then install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
  */
 int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 {
@@ -249,8 +256,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 }
 
 /*
- * Install a session keyring, discarding the old one.  If a keyring is not
- * supplied, an empty one is invented.
+ * Install the given keyring as the session keyring of the current task,
+ * replacing the existing one if any.  If the given keyring is NULL, then
+ * install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
  */
 static int install_session_keyring(struct key *keyring)
 {
index 3f4efcb..3490d21 100644 (file)
@@ -265,6 +265,10 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
        /* NOTE: overflow flag is not cleared */
        spin_unlock_irqrestore(&f->lock, flags);
 
+       /* close the old pool and wait until all users are gone */
+       snd_seq_pool_mark_closing(oldpool);
+       snd_use_lock_sync(&f->use_lock);
+
        /* release cells in old pool */
        for (cell = oldhead; cell; cell = next) {
                next = cell->next;
index 1d4f343..46a3403 100644 (file)
@@ -4831,6 +4831,7 @@ enum {
        ALC292_FIXUP_DISABLE_AAMIX,
        ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK,
        ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
        ALC275_FIXUP_DELL_XPS,
        ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
        ALC293_FIXUP_LENOVO_SPK_NOISE,
@@ -5429,6 +5430,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE
        },
+       [ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
        [ALC275_FIXUP_DELL_XPS] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -5501,7 +5511,7 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc298_fixup_speaker_volume,
                .chained = true,
-               .chain_id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+               .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
        },
        [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
                .type = HDA_FIXUP_PINS,
index 8276675..78a9856 100644 (file)
@@ -343,7 +343,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
 }
 
 #define CLASSD_ACLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
-#define CLASSD_ACLK_RATE_12M288_MPY_8  (12228 * 1000 * 8)
+#define CLASSD_ACLK_RATE_12M288_MPY_8  (12288 * 1000 * 8)
 
 static struct {
        int rate;
index c607457..6c702c8 100644 (file)
@@ -30,6 +30,7 @@
 #include "msm-digital-cdc.h"
 #include "msm-cdc-common.h"
 #include "../../msm/sdm660-common.h"
+#include "../../../../drivers/base/regmap/internal.h"
 
 #define DRV_NAME "msm_digital_codec"
 #define MCLK_RATE_9P6MHZ        9600000
@@ -71,6 +72,8 @@ static int msm_digcdc_clock_control(bool flag)
 {
        int ret = -EINVAL;
        struct msm_asoc_mach_data *pdata = NULL;
+       struct msm_dig_priv *msm_dig_cdc =
+                               snd_soc_codec_get_drvdata(registered_digcodec);
 
        pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
 
@@ -84,6 +87,12 @@ static int msm_digcdc_clock_control(bool flag)
                        if (ret < 0) {
                                pr_err("%s:failed to enable the MCLK\n",
                                       __func__);
+                               /*
+                                * Avoid access to lpass register
+                                * as clock enable failed during SSR.
+                                */
+                               if (ret == -ENODEV)
+                                       msm_dig_cdc->regmap->cache_only = true;
                                mutex_unlock(&pdata->cdc_int_mclk0_mutex);
                                return ret;
                        }
index fff1fdc..c9babac 100644 (file)
@@ -452,8 +452,23 @@ bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
 bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       /* cache bypass for initial version */
-       default:
+       case MSM89XX_CDC_CORE_RX1_B1_CTL:
+       case MSM89XX_CDC_CORE_RX2_B1_CTL:
+       case MSM89XX_CDC_CORE_RX3_B1_CTL:
+       case MSM89XX_CDC_CORE_RX1_B6_CTL:
+       case MSM89XX_CDC_CORE_RX2_B6_CTL:
+       case MSM89XX_CDC_CORE_RX3_B6_CTL:
+       case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG:
+       case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG:
+       case MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG:
+       case MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG:
+       case MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG:
+       case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL:
+       case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL:
+       case MSM89XX_CDC_CORE_CLK_MCLK_CTL:
+       case MSM89XX_CDC_CORE_CLK_PDM_CTL:
                return true;
+       default:
+               return false;
        }
 }
index d4db55f..24672f4 100644 (file)
@@ -9,7 +9,7 @@ snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
                                 msm-dai-stub-v2.o
 obj-$(CONFIG_SND_HWDEP) += msm-pcm-routing-devdep.o
-obj-$(CONFIG_DTS_EAGLE) += msm-dts-eagle.o
+obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
 obj-$(CONFIG_DOLBY_DS2) += msm-ds2-dap-config.o
 obj-$(CONFIG_DOLBY_LICENSE) += msm-ds2-dap-config.o
 obj-$(CONFIG_DTS_SRS_TM) += msm-dts-srs-tm-config.o
index b54cde4..0194dc4 100644 (file)
@@ -158,9 +158,6 @@ size_t get_cal_info_size(int32_t cal_type)
        case ULP_LSM_CAL_TYPE:
                size = sizeof(struct audio_cal_info_lsm);
                break;
-       case DTS_EAGLE_CAL_TYPE:
-               size = 0;
-               break;
        case AUDIO_CORE_METAINFO_CAL_TYPE:
                size = sizeof(struct audio_cal_info_metainfo);
                break;
@@ -307,9 +304,6 @@ size_t get_user_cal_type_size(int32_t cal_type)
        case ULP_LSM_CAL_TYPE:
                size = sizeof(struct audio_cal_type_lsm);
                break;
-       case DTS_EAGLE_CAL_TYPE:
-               size = 0;
-               break;
        case AUDIO_CORE_METAINFO_CAL_TYPE:
                size = sizeof(struct audio_cal_type_metainfo);
                break;
index 1c08842..e312a87 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -15,7 +15,6 @@
 #include <sound/q6asm-v2.h>
 #include <sound/compress_params.h>
 #include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
 #include <sound/devdep_params.h>
 
 #define MAX_ENABLE_CMD_SIZE 32
@@ -49,26 +48,6 @@ bool msm_audio_effects_is_effmodule_supp_in_top(int effect_module,
        case EQ_MODULE:
                switch (topology) {
                case ASM_STREAM_POSTPROC_TOPO_ID_SA_PLUS:
-               case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
-               case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-                       return true;
-               default:
-                       return false;
-               }
-       case DTS_EAGLE_MODULE:
-               switch (topology) {
-               case ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX:
-               case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
-               case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-                       return true;
-               default:
-                       return false;
-               }
-       case SOFT_VOLUME2_MODULE:
-       case DTS_EAGLE_MODULE_ENABLE:
-               switch (topology) {
-               case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
-               case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
                        return true;
                default:
                        return false;
@@ -276,7 +255,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
                        break;
                }
        }
-       if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+       if (params_length && (rc == 0))
                q6asm_send_audio_effects_params(ac, params,
                                                params_length);
        else
@@ -747,7 +726,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
                        break;
                }
        }
-       if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+       if (params_length && (rc == 0))
                q6asm_send_audio_effects_params(ac, params,
                                                params_length);
        else
@@ -883,7 +862,7 @@ int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
                        break;
                }
        }
-       if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+       if (params_length && (rc == 0))
                q6asm_send_audio_effects_params(ac, params,
                                                params_length);
        else
@@ -1223,7 +1202,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
                        break;
                }
        }
-       if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+       if (params_length && (rc == 0))
                q6asm_send_audio_effects_params(ac, params,
                                                params_length);
        else
index 8fc0913..5bd3b6d 100644 (file)
@@ -42,8 +42,6 @@
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
 #include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
-
 #include "msm-pcm-routing-v2.h"
 #include "msm-qti-pp-config.h"
 
@@ -80,15 +78,6 @@ const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
 
 #define MAX_NUMBER_OF_STREAMS 2
 
-/*
- * Max size for getting DTS EAGLE Param through kcontrol
- * Safe for both 32 and 64 bit platforms
- * 64 = size of kcontrol value array on 64 bit platform
- * 4 = size of parameters Eagle expects before cast to 64 bits
- * 40 = size of dts_eagle_param_desc + module_id cast to 64 bits
- */
-#define DTS_EAGLE_MAX_PARAM_SIZE_FOR_ALSA ((64 * 4) - 40)
-
 struct msm_compr_gapless_state {
        bool set_next_stream_id;
        int32_t stream_opened[MAX_NUMBER_OF_STREAMS];
@@ -378,11 +367,6 @@ static int msm_compr_set_volume(struct snd_compr_stream *cstream,
        if (rc < 0)
                pr_err("%s: Send vol gain command failed rc=%d\n",
                       __func__, rc);
-       else
-               if (msm_dts_eagle_set_stream_gain(prtd->audio_client,
-                                               volume_l, volume_r))
-                       pr_debug("%s: DTS_EAGLE send stream gain failed\n",
-                               __func__);
 
        return rc;
 }
@@ -1215,26 +1199,6 @@ static int msm_compr_init_pp_params(struct snd_compr_stream *cstream,
        };
 
        switch (ac->topology) {
-       case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS: /* HPX + SA+ topology */
-
-               ret = q6asm_set_softvolume_v2(ac, &softvol,
-                                             SOFT_VOLUME_INSTANCE_1);
-               if (ret < 0)
-                       pr_err("%s: Send SoftVolume Param failed ret=%d\n",
-                       __func__, ret);
-
-               ret = q6asm_set_softvolume_v2(ac, &softvol,
-                                             SOFT_VOLUME_INSTANCE_2);
-               if (ret < 0)
-                       pr_err("%s: Send SoftVolume2 Param failed ret=%d\n",
-                       __func__, ret);
-               /*
-                * HPX module init is trigerred from HAL using ioctl
-                * DTS_EAGLE_MODULE_ENABLE when stream starts
-                */
-               break;
-       case ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX: /* HPX topology */
-               break;
        default:
                ret = q6asm_set_softvolume_v2(ac, &softvol,
                                              SOFT_VOLUME_INSTANCE_1);
@@ -3133,23 +3097,6 @@ static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol,
                                                    &(audio_effects->equalizer),
                                                     values);
                break;
-       case DTS_EAGLE_MODULE:
-               pr_debug("%s: DTS_EAGLE_MODULE\n", __func__);
-               if (!msm_audio_effects_is_effmodule_supp_in_top(effects_module,
-                                               prtd->audio_client->topology))
-                       return 0;
-               msm_dts_eagle_handle_asm(NULL, (void *)values, true,
-                                        false, prtd->audio_client, NULL);
-               break;
-       case DTS_EAGLE_MODULE_ENABLE:
-               pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__);
-               if (msm_audio_effects_is_effmodule_supp_in_top(effects_module,
-                                               prtd->audio_client->topology))
-                       msm_dts_eagle_enable_asm(prtd->audio_client,
-                                       (bool)values[0],
-                                       AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-
-               break;
        case SOFT_VOLUME_MODULE:
                pr_debug("%s: SOFT_VOLUME_MODULE\n", __func__);
                break;
@@ -3178,7 +3125,6 @@ static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
        struct msm_compr_audio_effects *audio_effects = NULL;
        struct snd_compr_stream *cstream = NULL;
        struct msm_compr_audio *prtd = NULL;
-       long *values = &(ucontrol->value.integer.value[0]);
 
        pr_debug("%s\n", __func__);
        if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3198,28 +3144,6 @@ static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        }
 
-       switch (audio_effects->query.mod_id) {
-       case DTS_EAGLE_MODULE:
-               pr_debug("%s: DTS_EAGLE_MODULE handling queued get\n",
-                        __func__);
-               values[0] = (long)audio_effects->query.mod_id;
-               values[1] = (long)audio_effects->query.parm_id;
-               values[2] = (long)audio_effects->query.size;
-               values[3] = (long)audio_effects->query.offset;
-               values[4] = (long)audio_effects->query.device;
-               if (values[2] > DTS_EAGLE_MAX_PARAM_SIZE_FOR_ALSA) {
-                       pr_err("%s: DTS_EAGLE_MODULE parameter's requested size (%li) too large (max size is %i)\n",
-                               __func__, values[2],
-                               DTS_EAGLE_MAX_PARAM_SIZE_FOR_ALSA);
-                       return -EINVAL;
-               }
-               msm_dts_eagle_handle_asm(NULL, (void *)&values[1],
-                                        true, true, prtd->audio_client, NULL);
-               break;
-       default:
-               pr_err("%s: Invalid effects config module\n", __func__);
-               return -EINVAL;
-       }
        return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dts-eagle.c b/sound/soc/msm/qdsp6v2/msm-dts-eagle.c
deleted file mode 100644 (file)
index 15845b2..0000000
+++ /dev/null
@@ -1,1625 +0,0 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/msm_ion.h>
-#include <linux/mm.h>
-#include <linux/msm_audio_ion.h>
-#include <linux/vmalloc.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/pcm.h>
-#include <sound/q6adm-v2.h>
-#include <sound/q6asm-v2.h>
-#include <sound/apr_audio-v2.h>
-#include <sound/q6audio-v2.h>
-#include <sound/audio_effects.h>
-#include <sound/hwdep.h>
-#include <sound/msm-dts-eagle.h>
-#include <sound/q6core.h>
-
-#include "msm-pcm-routing-v2.h"
-
-#define ION_MEM_SIZE  131072
-#define DEPC_MAX_SIZE 524288
-
-#define MPST                           AUDPROC_MODULE_ID_DTS_HPX_POSTMIX
-#define MPRE                           AUDPROC_MODULE_ID_DTS_HPX_PREMIX
-
-#define eagle_vol_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER_VOLUME: " fmt "\n", ##__VA_ARGS__)
-#define eagle_vol_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER_VOLUME: " fmt "\n", ##__VA_ARGS__)
-#define eagle_drv_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER: " fmt "\n", ##__VA_ARGS__)
-#define eagle_drv_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER: " fmt "\n", ##__VA_ARGS__)
-#define eagle_precache_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER_SENDCACHE_PRE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_precache_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER_SENDCACHE_PRE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_postcache_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER_SENDCACHE_POST: " fmt "\n", ##__VA_ARGS__)
-#define eagle_postcache_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER_SENDCACHE_POST: " fmt "\n", ##__VA_ARGS__)
-#define eagle_ioctl_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER_IOCTL: " fmt "\n", ##__VA_ARGS__)
-#define eagle_ioctl_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER_IOCTL: " fmt "\n", ##__VA_ARGS__)
-#define eagle_asm_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER_ASM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_asm_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER_ASM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_adm_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_DRIVER_ADM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_adm_err(fmt, ...) \
-       pr_err("DTS_EAGLE_DRIVER_ADM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_enable_dbg(fmt, ...) \
-       pr_debug("DTS_EAGLE_ENABLE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_enable_err(fmt, ...) \
-       pr_err("DTS_EAGLE_ENABLE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_ioctl_info(fmt, ...) \
-       pr_err("DTS_EAGLE_IOCTL: " fmt "\n", ##__VA_ARGS__)
-
-enum {
-       AUDIO_DEVICE_OUT_EARPIECE = 0,
-       AUDIO_DEVICE_OUT_SPEAKER,
-       AUDIO_DEVICE_OUT_WIRED_HEADSET,
-       AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
-       AUDIO_DEVICE_OUT_BLUETOOTH_SCO,
-       AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
-       AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
-       AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
-       AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
-       AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
-       AUDIO_DEVICE_OUT_AUX_DIGITAL,
-       AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,
-       AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
-       AUDIO_DEVICE_OUT_USB_ACCESSORY,
-       AUDIO_DEVICE_OUT_USB_DEVICE,
-       AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-       AUDIO_DEVICE_OUT_ANC_HEADSET,
-       AUDIO_DEVICE_OUT_ANC_HEADPHONE,
-       AUDIO_DEVICE_OUT_PROXY,
-       AUDIO_DEVICE_OUT_FM,
-       AUDIO_DEVICE_OUT_FM_TX,
-
-       AUDIO_DEVICE_OUT_COUNT
-};
-
-#define AUDIO_DEVICE_COMBO 0x400000 /* bit 23 */
-
-enum { /* cache block */
-       CB_0 = 0,
-       CB_1,
-       CB_2,
-       CB_3,
-       CB_4,
-       CB_5,
-       CB_6,
-       CB_7,
-
-       CB_COUNT
-};
-
-enum { /* cache block description */
-       CBD_DEV_MASK = 0,
-       CBD_OFFSG,
-       CBD_CMD0,
-       CBD_SZ0,
-       CBD_OFFS1,
-       CBD_CMD1,
-       CBD_SZ1,
-       CBD_OFFS2,
-       CBD_CMD2,
-       CBD_SZ2,
-       CBD_OFFS3,
-       CBD_CMD3,
-       CBD_SZ3,
-
-       CBD_COUNT,
-};
-
-static s32 _fx_logN(s32 x)
-{
-       s32 t, y = 0xa65af;
-       if (x < 0x00008000) {
-               x <<= 16; y -= 0xb1721; }
-       if (x < 0x00800000) {
-               x <<= 8; y -= 0x58b91; }
-       if (x < 0x08000000) {
-               x <<= 4; y -= 0x2c5c8; }
-       if (x < 0x20000000) {
-               x <<= 2; y -= 0x162e4; }
-       if (x < 0x40000000) {
-               x <<= 1; y -= 0x0b172; }
-       t = x + (x >> 1);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x067cd; }
-       t = x + (x >> 2);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x03920; }
-       t = x + (x >> 3);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x01e27; }
-       t = x + (x >> 4);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x00f85; }
-       t = x + (x >> 5);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x007e1; }
-       t = x + (x >> 6);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x003f8; }
-       t = x + (x >> 7);
-       if ((t & 0x80000000) == 0) {
-               x = t; y -= 0x001fe; }
-       x = 0x80000000 - x;
-       y -= x >> 15;
-       return y;
-}
-
-static inline void *_getd(struct dts_eagle_param_desc *depd)
-{
-       return (void *)(((char *)depd) + sizeof(struct dts_eagle_param_desc));
-}
-
-static int _ref_cnt;
-/* dts eagle parameter cache */
-static char *_depc;
-static u32 _depc_size;
-static s32 _c_bl[CB_COUNT][CBD_COUNT];
-static u32 _device_primary;
-static u32 _device_all;
-/* ION states */
-static struct ion_client *_ion_client;
-static struct ion_handle *_ion_handle;
-static struct param_outband _po;
-static struct audio_client *_ac_NT;
-static struct ion_client *_ion_client_NT;
-static struct ion_handle *_ion_handle_NT;
-static struct param_outband _po_NT;
-
-#define SEC_BLOB_MAX_CNT 10
-#define SEC_BLOB_MAX_SIZE 0x4004 /*extra 4 for size*/
-static char *_sec_blob[SEC_BLOB_MAX_CNT];
-
-/* multi-copp support */
-static int _cidx[AFE_MAX_PORTS] = {-1};
-
-/* volume controls */
-#define VOL_CMD_CNT_MAX 10
-static u32 _vol_cmd_cnt;
-static s32 **_vol_cmds;
-struct vol_cmds_d {
-       s32 d[4];
-};
-static struct vol_cmds_d *_vol_cmds_d;
-static const s32 _log10_10_inv_x20 = 0x0008af84;
-
-/* hpx master control */
-static u32 _is_hpx_enabled;
-
-static void _volume_cmds_free(void)
-{
-       int i;
-       for (i = 0; i < _vol_cmd_cnt; i++)
-               kfree(_vol_cmds[i]);
-       _vol_cmd_cnt = 0;
-       kfree(_vol_cmds);
-       kfree(_vol_cmds_d);
-       _vol_cmds = NULL;
-       _vol_cmds_d = NULL;
-}
-
-static s32 _volume_cmds_alloc1(s32 size)
-{
-       _volume_cmds_free();
-       _vol_cmd_cnt = size;
-       _vol_cmds = kzalloc(_vol_cmd_cnt * sizeof(int *), GFP_KERNEL);
-       if (_vol_cmds) {
-               _vol_cmds_d = kzalloc(_vol_cmd_cnt * sizeof(struct vol_cmds_d),
-                                       GFP_KERNEL);
-       } else
-               _vol_cmd_cnt = 0;
-       if (_vol_cmds_d)
-               return 0;
-       _volume_cmds_free();
-       return -ENOMEM;
-}
-
-/* assumes size is equal or less than 0xFFF */
-static s32 _volume_cmds_alloc2(s32 idx, s32 size)
-{
-       kfree(_vol_cmds[idx]);
-       _vol_cmds[idx] = kzalloc(size, GFP_KERNEL);
-       if (_vol_cmds[idx])
-               return 0;
-       _vol_cmds_d[idx].d[0] = 0;
-       return -ENOMEM;
-}
-
-static void _init_cb_descs(void)
-{
-       int i;
-       for (i = 0; i < CB_COUNT; i++) {
-               _c_bl[i][CBD_DEV_MASK] = 0;
-               _c_bl[i][CBD_OFFSG] = _c_bl[i][CBD_OFFS1] =
-               _c_bl[i][CBD_OFFS2] = _c_bl[i][CBD_OFFS3] =
-               0xFFFFFFFF;
-               _c_bl[i][CBD_CMD0] = _c_bl[i][CBD_SZ0] =
-               _c_bl[i][CBD_CMD1] = _c_bl[i][CBD_SZ1] =
-               _c_bl[i][CBD_CMD2] = _c_bl[i][CBD_SZ2] =
-               _c_bl[i][CBD_CMD3] = _c_bl[i][CBD_SZ3] = 0;
-       }
-}
-
-static u32 _get_dev_mask_for_pid(int pid)
-{
-       switch (pid) {
-       case SLIMBUS_0_RX:
-               return (1 << AUDIO_DEVICE_OUT_EARPIECE) |
-                       (1 << AUDIO_DEVICE_OUT_SPEAKER) |
-                       (1 << AUDIO_DEVICE_OUT_WIRED_HEADSET) |
-                       (1 << AUDIO_DEVICE_OUT_WIRED_HEADPHONE) |
-                       (1 << AUDIO_DEVICE_OUT_ANC_HEADSET) |
-                       (1 << AUDIO_DEVICE_OUT_ANC_HEADPHONE);
-       case INT_BT_SCO_RX:
-               return (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) |
-                       (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) |
-                       (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
-       case RT_PROXY_PORT_001_RX:
-               return (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) |
-                       (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) |
-                       (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) |
-                       (1 << AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) |
-                       (1 << AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) |
-                       (1 << AUDIO_DEVICE_OUT_USB_ACCESSORY) |
-                       (1 << AUDIO_DEVICE_OUT_USB_DEVICE) |
-                       (1 << AUDIO_DEVICE_OUT_PROXY);
-       case HDMI_RX:
-               return 1 << AUDIO_DEVICE_OUT_AUX_DIGITAL;
-       case INT_FM_RX:
-               return 1 << AUDIO_DEVICE_OUT_FM;
-       case INT_FM_TX:
-               return 1 << AUDIO_DEVICE_OUT_FM_TX;
-       default:
-               return 0;
-       }
-}
-
-static int _get_pid_from_dev(u32 device)
-{
-       if (device & (1 << AUDIO_DEVICE_OUT_EARPIECE) ||
-           device & (1 << AUDIO_DEVICE_OUT_SPEAKER) ||
-           device & (1 << AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
-           device & (1 << AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
-           device & (1 << AUDIO_DEVICE_OUT_ANC_HEADSET) ||
-           device & (1 << AUDIO_DEVICE_OUT_ANC_HEADPHONE)) {
-               return SLIMBUS_0_RX;
-       } else if (device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) ||
-                  device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
-                  device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
-               return INT_BT_SCO_RX;
-       } else if (device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) ||
-                  device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) ||
-                  device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
-                  device & (1 << AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) ||
-                  device & (1 << AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ||
-                  device & (1 << AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
-                  device & (1 << AUDIO_DEVICE_OUT_USB_DEVICE) ||
-                  device & (1 << AUDIO_DEVICE_OUT_PROXY)) {
-               return RT_PROXY_PORT_001_RX;
-       } else if (device & (1 << AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
-               return HDMI_RX;
-       } else if (device & (1 << AUDIO_DEVICE_OUT_FM)) {
-               return INT_FM_RX;
-       } else if (device & (1 << AUDIO_DEVICE_OUT_FM_TX)) {
-               return INT_FM_TX;
-       }
-       return 0;
-}
-
-static s32 _get_cb_for_dev(int device)
-{
-       s32 i;
-       if (device & AUDIO_DEVICE_COMBO) {
-               for (i = 0; i < CB_COUNT; i++) {
-                       if ((_c_bl[i][CBD_DEV_MASK] & device) == device)
-                               return i;
-               }
-       } else {
-               for (i = 0; i < CB_COUNT; i++) {
-                       if ((_c_bl[i][CBD_DEV_MASK] & device) &&
-                           !(_c_bl[i][CBD_DEV_MASK] & AUDIO_DEVICE_COMBO))
-                               return i;
-               }
-       }
-       eagle_drv_err("%s: device %i not found", __func__, device);
-       return -EINVAL;
-}
-
-static int _is_port_open_and_eagle(int pid)
-{
-       if (msm_routing_check_backend_enabled(pid))
-               return 1;
-       return 1;
-}
-
-static int _isNTDevice(u32 device)
-{
-       if (device &
-               ((1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) |
-               (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) |
-               (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) |
-               (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) |
-               (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) |
-               (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) |
-               (1 << AUDIO_DEVICE_OUT_AUX_DIGITAL)))
-               return 1;
-       return 0;
-}
-
-static void _reg_ion_mem(void)
-{
-       int rc;
-       rc = msm_audio_ion_alloc("DTS_EAGLE", &_ion_client, &_ion_handle,
-                           ION_MEM_SIZE, &_po.paddr, &_po.size, &_po.kvaddr);
-       if (rc)
-               eagle_drv_err("%s: msm audio ion alloc failed with %i",
-                               __func__, rc);
-}
-
-static void _unreg_ion_mem(void)
-{
-       int rc;
-       rc = msm_audio_ion_free(_ion_client, _ion_handle);
-       if (rc)
-               eagle_drv_err("%s: msm audio ion alloc failed with %i",
-                               __func__, rc);
-}
-
-static void _reg_ion_mem_NT(void)
-{
-       int rc;
-       eagle_drv_dbg("%s: NT ion mem", __func__);
-       rc = msm_audio_ion_alloc("DTS_EAGLE", &_ion_client_NT,
-                                &_ion_handle_NT, ION_MEM_SIZE,
-                                &_po_NT.paddr, &_po_NT.size, &_po_NT.kvaddr);
-       if (rc) {
-               eagle_drv_err("%s: msm audio ion alloc failed", __func__);
-               return;
-       }
-       rc = q6asm_memory_map(_ac_NT, _po_NT.paddr,
-                             IN, _po_NT.size, 1);
-       if (rc < 0) {
-               eagle_drv_err("%s: memory map failed", __func__);
-               msm_audio_ion_free(_ion_client_NT, _ion_handle_NT);
-               _ion_client_NT = NULL;
-               _ion_handle_NT = NULL;
-       }
-}
-
-static void _unreg_ion_mem_NT(void)
-{
-       int rc;
-       rc = q6asm_memory_unmap(_ac_NT, _po_NT.paddr, IN);
-       if (rc < 0)
-               eagle_drv_err("%s: mem unmap failed", __func__);
-       rc = msm_audio_ion_free(_ion_client_NT, _ion_handle_NT);
-       if (rc < 0)
-               eagle_drv_err("%s: mem free failed", __func__);
-
-       _ion_client_NT = NULL;
-       _ion_handle_NT = NULL;
-}
-
-static struct audio_client *_getNTDeviceAC(void)
-{
-       return _ac_NT;
-}
-
-static void _set_audioclient(struct audio_client *ac)
-{
-       _ac_NT = ac;
-       _reg_ion_mem_NT();
-}
-
-static void _clear_audioclient(void)
-{
-       _unreg_ion_mem_NT();
-       _ac_NT = NULL;
-}
-
-
-static int _sendcache_pre(struct audio_client *ac)
-{
-       uint32_t offset, size;
-       int32_t cidx, cmd, err = 0;
-       cidx = _get_cb_for_dev(_device_primary);
-       if (cidx < 0) {
-               eagle_precache_err("%s: no cache for primary device %i found",
-                       __func__, _device_primary);
-               return -EINVAL;
-       }
-       offset = _c_bl[cidx][CBD_OFFSG];
-       cmd = _c_bl[cidx][CBD_CMD0];
-       size = _c_bl[cidx][CBD_SZ0];
-       /* check for integer overflow */
-       if (offset > (UINT_MAX - size))
-               err = -EINVAL;
-       if ((_depc_size == 0) || !_depc || (size == 0) ||
-               cmd == 0 || ((offset + size) > _depc_size) || (err != 0)) {
-               eagle_precache_err("%s: primary device %i cache index %i general error - cache size = %u, cache ptr = %pK, offset = %u, size = %u, cmd = %i",
-                       __func__, _device_primary, cidx, _depc_size, _depc,
-                       offset, size, cmd);
-               return -EINVAL;
-       }
-
-       if ((offset < (UINT_MAX - 124)) && ((offset + 124) < _depc_size))
-               eagle_precache_dbg("%s: first 6 integers %i %i %i %i %i %i (30th %i)",
-                       __func__, *((int *)&_depc[offset]),
-                       *((int *)&_depc[offset+4]),
-                       *((int *)&_depc[offset+8]),
-                       *((int *)&_depc[offset+12]),
-                       *((int *)&_depc[offset+16]),
-                       *((int *)&_depc[offset+20]),
-                       *((int *)&_depc[offset+120]));
-       eagle_precache_dbg("%s: sending full data block to port, with cache index = %d device mask 0x%X, param = 0x%X, offset = %u, and size = %u",
-                 __func__, cidx, _c_bl[cidx][CBD_DEV_MASK], cmd, offset, size);
-
-       if (q6asm_dts_eagle_set(ac, cmd, size, (void *)&_depc[offset],
-                               NULL, MPRE))
-               eagle_precache_err("%s: q6asm_dts_eagle_set failed with id = %d and size = %u",
-                       __func__, cmd, size);
-       else
-               eagle_precache_dbg("%s: q6asm_dts_eagle_set succeeded with id = %d and size = %u",
-                        __func__, cmd, size);
-       return 0;
-}
-
-static int _sendcache_post(int port_id, int copp_idx, int topology)
-{
-       int cidx = -1, cmd, mask, index, err = 0;
-       uint32_t offset, size;
-
-       if (port_id == -1) {
-               cidx = _get_cb_for_dev(_device_primary);
-               if (cidx < 0) {
-                       eagle_postcache_err("%s: no cache for primary device %i found. Port id was 0x%X",
-                               __func__, _device_primary, port_id);
-                       return -EINVAL;
-               }
-               goto NT_MODE_GOTO;
-       }
-
-       index = adm_validate_and_get_port_index(port_id);
-       if (index < 0) {
-               eagle_postcache_err("%s: Invalid port idx %d port_id %#x",
-                       __func__, index, port_id);
-               return -EINVAL;
-       }
-       eagle_postcache_dbg("%s: valid port idx %d for port_id %#x set to %i",
-               __func__, index, port_id, copp_idx);
-       _cidx[index] = copp_idx;
-
-       mask = _get_dev_mask_for_pid(port_id);
-       if (mask & _device_primary) {
-               cidx = _get_cb_for_dev(_device_primary);
-               if (cidx < 0) {
-                       eagle_postcache_err("%s: no cache for primary device %i found. Port id was 0x%X",
-                               __func__, _device_primary, port_id);
-                       return -EINVAL;
-               }
-       } else if (mask & _device_all) {
-               cidx = _get_cb_for_dev(_device_all);
-               if (cidx < 0) {
-                       eagle_postcache_err("%s: no cache for combo device %i found. Port id was 0x%X",
-                               __func__, _device_all, port_id);
-                       return -EINVAL;
-               }
-       } else {
-               eagle_postcache_err("%s: port id 0x%X not for primary or combo device %i",
-                       __func__, port_id, _device_primary);
-               return -EINVAL;
-       }
-
-NT_MODE_GOTO:
-       offset = _c_bl[cidx][CBD_OFFSG] + _c_bl[cidx][CBD_OFFS2];
-       cmd = _c_bl[cidx][CBD_CMD2];
-       size = _c_bl[cidx][CBD_SZ2];
-
-       /* check for integer overflow */
-       if (offset > (UINT_MAX - size))
-               err = -EINVAL;
-       if ((_depc_size == 0) || !_depc || (err != 0) || (size == 0) ||
-               (cmd == 0) || (offset + size) > _depc_size) {
-               eagle_postcache_err("%s: primary device %i cache index %i port_id 0x%X general error - cache size = %u, cache ptr = %pK, offset = %u, size = %u, cmd = %i",
-                       __func__, _device_primary, cidx, port_id,
-                       _depc_size, _depc, offset, size, cmd);
-               return -EINVAL;
-       }
-
-       if ((offset < (UINT_MAX - 24)) && ((offset + 24) < _depc_size))
-               eagle_postcache_dbg("%s: first 6 integers %i %i %i %i %i %i",
-                       __func__, *((int *)&_depc[offset]),
-                       *((int *)&_depc[offset+4]),
-                       *((int *)&_depc[offset+8]),
-                       *((int *)&_depc[offset+12]),
-                       *((int *)&_depc[offset+16]),
-                       *((int *)&_depc[offset+20]));
-       eagle_postcache_dbg("%s: sending full data block to port, with cache index = %d device mask 0x%X, port_id = 0x%X, param = 0x%X, offset = %u, and size = %u",
-               __func__, cidx, _c_bl[cidx][CBD_DEV_MASK], port_id, cmd,
-               offset, size);
-
-       if (_ac_NT) {
-               eagle_postcache_dbg("%s: NT Route detected", __func__);
-               if (q6asm_dts_eagle_set(_getNTDeviceAC(), cmd, size,
-                                       (void *)&_depc[offset],
-                                       &_po_NT, MPST))
-                       eagle_postcache_err("%s: q6asm_dts_eagle_set failed with id = 0x%X and size = %u",
-                               __func__, cmd, size);
-       } else if (adm_dts_eagle_set(port_id, copp_idx, cmd,
-                             (void *)&_depc[offset], size) < 0)
-               eagle_postcache_err("%s: adm_dts_eagle_set failed with id = 0x%X and size = %u",
-                       __func__, cmd, size);
-       else
-               eagle_postcache_dbg("%s: adm_dts_eagle_set succeeded with id = 0x%X and size = %u",
-                        __func__, cmd, size);
-       return 0;
-}
-
-static int _enable_post_get_control(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = _is_hpx_enabled;
-       return 0;
-}
-
-static int _enable_post_put_control(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       int idx = 0, be_index = 0, port_id, topology;
-       int flag = ucontrol->value.integer.value[0];
-       struct msm_pcm_routing_bdai_data msm_bedai;
-       eagle_drv_dbg("%s: flag %d", __func__, flag);
-
-       _is_hpx_enabled = flag ? true : false;
-       msm_pcm_routing_acquire_lock();
-       /* send cache postmix params when hpx is set On */
-       for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
-               msm_pcm_routing_get_bedai_info(be_index, &msm_bedai);
-               port_id = msm_bedai.port_id;
-               if (!(((port_id == SLIMBUS_0_RX) ||
-                     (port_id == RT_PROXY_PORT_001_RX)) &&
-                     msm_bedai.active))
-                       continue;
-               for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
-                       topology = adm_get_topology_for_port_copp_idx(
-                                                               port_id, idx);
-                       if (topology ==
-                               ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) {
-                               msm_dts_eagle_enable_adm(port_id, idx,
-                                                        _is_hpx_enabled);
-                       }
-               }
-       }
-       msm_pcm_routing_release_lock();
-       return 0;
-}
-
-static const struct snd_kcontrol_new _hpx_enabled_controls[] = {
-       SOC_SINGLE_EXT("Set HPX OnOff", SND_SOC_NOPM, 0, 1, 0,
-       _enable_post_get_control, _enable_post_put_control)
-};
-
-/**
- * msm_dts_ion_memmap() - helper function to map ION memory
- * @po_:       Out of band memory structure used as memory.
- *
- * Assign already allocated ION memory for mapping it to dsp.
- *
- * Return: No return value.
- */
-void msm_dts_ion_memmap(struct param_outband *po_)
-{
-       po_->size = ION_MEM_SIZE;
-       po_->kvaddr = _po.kvaddr;
-       po_->paddr = _po.paddr;
-}
-
-/**
- * msm_dts_eagle_enable_asm() - Enable/disable dts module
- * @ac:        Enable/disable module in ASM session associated with this audio client.
- * @enable:    Enable/disable the dts module.
- * @module:    module id.
- *
- * Enable/disable specified dts module id in asm.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_enable_asm(struct audio_client *ac, u32 enable, int module)
-{
-       int ret = 0;
-       eagle_enable_dbg("%s: enable = %i on module %i",
-                __func__, enable, module);
-       _is_hpx_enabled = enable;
-       ret = q6asm_dts_eagle_set(ac, AUDPROC_PARAM_ID_ENABLE,
-                                     sizeof(enable), &enable,
-                                     NULL, module);
-       if (_is_hpx_enabled) {
-               if (module == MPRE)
-                       _sendcache_pre(ac);
-               else if (module == MPST)
-                       _sendcache_post(-1, 0, 0);
-       }
-       return ret;
-}
-
-/**
- * msm_dts_eagle_enable_adm() - Enable/disable dts module in adm
- * @port_id:   Send enable/disable param to this port id.
- * @copp_idx:  Send enable/disable param to the relevant copp.
- * @enable:    Enable/disable the dts module.
- *
- * Enable/disable dts module in adm.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_enable_adm(int port_id, int copp_idx, u32 enable)
-{
-       int ret = 0;
-       eagle_enable_dbg("%s: enable = %i", __func__, enable);
-       _is_hpx_enabled = enable;
-       ret = adm_dts_eagle_set(port_id, copp_idx, AUDPROC_PARAM_ID_ENABLE,
-                            (char *)&enable, sizeof(enable));
-       if (_is_hpx_enabled)
-               _sendcache_post(port_id, copp_idx, MPST);
-       return ret;
-}
-
-/**
- * msm_dts_eagle_add_controls() -  Add mixer control to Enable/Disable DTS HPX
- * @platform:  Add mixer controls to this platform.
- *
- * Add mixer control to Enable/Disable DTS HPX module in ADM.
- *
- * Return: No return value.
- */
-void msm_dts_eagle_add_controls(struct snd_soc_platform *platform)
-{
-       snd_soc_add_platform_controls(platform, _hpx_enabled_controls,
-                                     ARRAY_SIZE(_hpx_enabled_controls));
-}
-
-/**
- * msm_dts_eagle_set_stream_gain() -  Set stream gain to DTS Premix module
- * @ac:        Set stream gain to ASM session associated with this audio client.
- * @lgain:     Left gain value.
- * @rgain:     Right gain value.
- *
- * Set stream gain to DTS Premix module in ASM.
- *
- * Return: failure or success.
- */
-int msm_dts_eagle_set_stream_gain(struct audio_client *ac, int lgain, int rgain)
-{
-       u32 i, val;
-       s32 idx, err = 0;
-
-       eagle_vol_dbg("%s: - entry: vol_cmd_cnt = %u, lgain = %i, rgain = %i",
-                __func__, _vol_cmd_cnt, lgain, rgain);
-
-       if (_depc_size == 0) {
-               eagle_vol_dbg("%s: driver cache not initialized", __func__);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < _vol_cmd_cnt; i++) {
-               if (_vol_cmds_d[i].d[0] & 0x8000) {
-                       idx = (sizeof(struct dts_eagle_param_desc)/sizeof(int))
-                               + (_vol_cmds_d[i].d[0] & 0x3FF);
-                       val = _fx_logN(((s32)(lgain+rgain)) << 2);
-                       val = ((long long)val * _log10_10_inv_x20) >> 16;
-                       _vol_cmds[i][idx] = (s32)clamp((int)(((long long)val *
-                                                   _vol_cmds_d[i].d[1]) >> 16),
-                                                   _vol_cmds_d[i].d[2],
-                                                   _vol_cmds_d[i].d[3]);
-                        eagle_vol_dbg("%s: loop %u cmd desc found %i, idx = %i. volume info: lgain = %i, rgain = %i, volume = %i (scale %i, min %i, max %i)",
-                                __func__, i, _vol_cmds_d[i].d[0], idx, lgain,
-                                rgain, _vol_cmds[i][idx], _vol_cmds_d[i].d[1],
-                                _vol_cmds_d[i].d[2], _vol_cmds_d[i].d[3]);
-               }
-               idx = _get_cb_for_dev(_device_primary);
-               if (idx < 0) {
-                       eagle_vol_err("%s: no cache for primary device %i found",
-                               __func__, _device_primary);
-                       return -EINVAL;
-               }
-               val = _c_bl[idx][CBD_OFFSG] + _vol_cmds[i][2];
-               /* check for integer overflow */
-               if (val > (UINT_MAX - _vol_cmds[i][1]))
-                       err = -EINVAL;
-               if ((err != 0) || ((val + _vol_cmds[i][1]) > _depc_size)) {
-                       eagle_vol_err("%s: volume size (%u) + offset (%i) out of bounds %i",
-                               __func__, val, _vol_cmds[i][1], _depc_size);
-                       return -EINVAL;
-               }
-               memcpy((void *)&_depc[val], &_vol_cmds[i][4], _vol_cmds[i][1]);
-               if (q6asm_dts_eagle_set(ac, _vol_cmds[i][0],
-                       _vol_cmds[i][1], (void *)&_depc[val], NULL, MPRE))
-                       eagle_vol_err("%s: loop %u - volume set failed with id 0x%X, size %i, offset %i, cmd_desc %i, scale %i, min %i, max %i, data(...) %i",
-                               __func__, i, _vol_cmds[i][0], _vol_cmds[i][1],
-                               _vol_cmds[i][2], _vol_cmds_d[i].d[0],
-                               _vol_cmds_d[i].d[1], _vol_cmds_d[i].d[2],
-                               _vol_cmds_d[i].d[3], _vol_cmds[i][4]);
-               else
-                       eagle_vol_dbg("%s: loop %u - volume set succeeded with id 0x%X, size %i, offset %i, cmd_desc %i, scale %i, min %i, max %i, data(...) %i",
-                                __func__, i, _vol_cmds[i][0], _vol_cmds[i][1],
-                                _vol_cmds[i][2], _vol_cmds_d[i].d[0],
-                                _vol_cmds_d[i].d[1], _vol_cmds_d[i].d[2],
-                                _vol_cmds_d[i].d[3], _vol_cmds[i][4]);
-       }
-       return 0;
-}
-
-/**
- * msm_dts_eagle_handle_asm() - Set or Get params from ASM
- * @depd:      DTS Eagle Params structure.
- * @buf:       Buffer to get queried param value.
- * @for_pre:   For premix module or postmix module.
- * @get:       Getting param from DSP or setting param.
- * @ac:        Set/Get from ASM session associated with this audio client.
- * @po:        Out of band memory to set or get postmix params.
- *
- * Set or Get params from modules in ASM session.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd, char *buf,
-                            bool for_pre, bool get, struct audio_client *ac,
-                            struct param_outband *po)
-{
-       struct dts_eagle_param_desc depd_ = {0};
-       s32 ret = 0, isALSA = 0, err = 0, i, mod = for_pre ? MPRE : MPST;
-       u32 offset;
-
-       eagle_asm_dbg("%s: set/get asm", __func__);
-
-       /* special handling for ALSA route, to accommodate 64 bit platforms */
-       if (depd == NULL) {
-               long *arg_ = (long *)buf;
-               depd = &depd_;
-               depd->id = (u32)*arg_++;
-               depd->size = (u32)*arg_++;
-               depd->offset = (s32)*arg_++;
-               depd->device = (u32)*arg_++;
-               buf = (char *)arg_;
-               isALSA = 1;
-       }
-
-       if (depd->size & 1) {
-               eagle_asm_err("%s: parameter size %u is not a multiple of 2",
-                       __func__, depd->size);
-               return -EINVAL;
-       }
-
-       if (get) {
-               void *buf_, *buf_m = NULL;
-               eagle_asm_dbg("%s: get requested", __func__);
-               if (depd->offset == -1) {
-                       eagle_asm_dbg("%s: get from dsp requested", __func__);
-                       if (depd->size > 0 && depd->size <= DEPC_MAX_SIZE) {
-                               buf_ = buf_m = vzalloc(depd->size);
-                       } else {
-                               eagle_asm_err("%s: get size %u invalid",
-                                             __func__, depd->size);
-                               return -EINVAL;
-                       }
-                       if (!buf_m) {
-                               eagle_asm_err("%s: out of memory", __func__);
-                               return -ENOMEM;
-                       } else if (q6asm_dts_eagle_get(ac, depd->id,
-                                                      depd->size, buf_m,
-                                                      po, mod) < 0) {
-                               eagle_asm_err("%s: asm get failed", __func__);
-                               ret = -EFAULT;
-                               goto DTS_EAGLE_IOCTL_GET_PARAM_PRE_EXIT;
-                       }
-                       eagle_asm_dbg("%s: get result: param id 0x%x value %d size %u",
-                                __func__, depd->id, *(int *)buf_m, depd->size);
-               } else {
-                       s32 tgt = _get_cb_for_dev(depd->device);
-                       if (tgt < 0) {
-                               eagle_asm_err("%s: no cache for device %u found",
-                                       __func__, depd->device);
-                               return -EINVAL;
-                       }
-                       offset = _c_bl[tgt][CBD_OFFSG] + depd->offset;
-                       /* check for integer overflow */
-                       if (offset > (UINT_MAX - depd->size))
-                               err = -EINVAL;
-                       if ((err != 0) || (offset + depd->size) > _depc_size) {
-                               eagle_asm_err("%s: invalid size %u and/or offset %u",
-                                       __func__, depd->size, offset);
-                               return -EINVAL;
-                       }
-                       buf_ = (u32 *)&_depc[offset];
-               }
-               if (isALSA) {
-                       if (depd->size == 2) {
-                               *(long *)buf = (long)*(__u16 *)buf_;
-                               eagle_asm_dbg("%s: asm out 16 bit value %li",
-                                               __func__, *(long *)buf);
-                       } else {
-                               s32 *pbuf = (s32 *)buf_;
-                               long *bufl = (long *)buf;
-                               for (i = 0; i < (depd->size >> 2); i++) {
-                                       *bufl++ = (long)*pbuf++;
-                                       eagle_asm_dbg("%s: asm out value %li",
-                                                        __func__, *(bufl-1));
-                               }
-                       }
-               } else {
-                       memcpy(buf, buf_, depd->size);
-               }
-DTS_EAGLE_IOCTL_GET_PARAM_PRE_EXIT:
-               vfree(buf_m);
-               return (int)ret;
-       } else {
-               s32 tgt = _get_cb_for_dev(depd->device);
-               if (tgt < 0) {
-                       eagle_asm_err("%s: no cache for device %u found",
-                               __func__, depd->device);
-                       return -EINVAL;
-               }
-               offset = _c_bl[tgt][CBD_OFFSG] + depd->offset;
-               /* check for integer overflow */
-               if (offset > (UINT_MAX - depd->size))
-                       err = -EINVAL;
-               if ((err != 0) || ((offset + depd->size) > _depc_size)) {
-                       eagle_asm_err("%s: invalid size %u and/or offset %u for parameter (cache is size %u)",
-                               __func__, depd->size, offset, _depc_size);
-                       return -EINVAL;
-               }
-               if (isALSA) {
-                       if (depd->size == 2) {
-                               *(__u16 *)&_depc[offset] = (__u16)*(long *)buf;
-                               eagle_asm_dbg("%s: asm in 16 bit value %li",
-                                               __func__, *(long *)buf);
-                       } else {
-                               s32 *pbuf = (s32 *)&_depc[offset];
-                               long *bufl = (long *)buf;
-                               for (i = 0; i < (depd->size >> 2); i++) {
-                                       *pbuf++ = (s32)*bufl++;
-                                       eagle_asm_dbg("%s: asm in value %i",
-                                                       __func__, *(pbuf-1));
-                               }
-                       }
-               } else {
-                       memcpy(&_depc[offset], buf, depd->size);
-               }
-               eagle_asm_dbg("%s: param info: param = 0x%X, size = %u, offset = %i, device = %u, cache block %i, global offset = %u, first bytes as integer = %i",
-                       __func__, depd->id, depd->size, depd->offset,
-                       depd->device,
-                       tgt, offset, *(int *)&_depc[offset]);
-               if (q6asm_dts_eagle_set(ac, depd->id, depd->size,
-                                       (void *)&_depc[offset], po, mod))
-                       eagle_asm_err("%s: q6asm_dts_eagle_set failed with id = 0x%X, size = %u, offset = %d",
-                               __func__, depd->id, depd->size, depd->offset);
-               else
-                       eagle_asm_dbg("%s: q6asm_dts_eagle_set succeeded with id = 0x%X, size = %u, offset = %d",
-                                __func__, depd->id, depd->size, depd->offset);
-       }
-       return (int)ret;
-}
-
-/**
- * msm_dts_eagle_handle_adm() - Set or Get params from ADM
- * @depd:      DTS Eagle Params structure used to set or get.
- * @buf:       Buffer to get queried param value in NT mode.
- * @for_pre:   For premix module or postmix module.
- * @get:       Getting param from DSP or setting param.
- *
- * Set or Get params from modules in ADM session.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd, char *buf,
-                            bool for_pre, bool get)
-{
-       u32 pid = _get_pid_from_dev(depd->device), cidx;
-       s32 ret = 0;
-
-       eagle_adm_dbg("%s: set/get adm", __func__);
-
-       if (_isNTDevice(depd->device)) {
-               eagle_adm_dbg("%s: NT Route detected", __func__);
-               ret = msm_dts_eagle_handle_asm(depd, buf, for_pre, get,
-                                              _getNTDeviceAC(), &_po_NT);
-               if (ret < 0)
-                       eagle_adm_err("%s: NT Route set failed with id = 0x%X, size = %u, offset = %i, device = %u",
-                               __func__, depd->id, depd->size, depd->offset,
-                               depd->device);
-       } else if (get) {
-               cidx = adm_validate_and_get_port_index(pid);
-               eagle_adm_dbg("%s: get from qdsp requested (port id 0x%X)",
-                        __func__, pid);
-               if (adm_dts_eagle_get(pid, _cidx[cidx], depd->id,
-                                     buf, depd->size) < 0) {
-                       eagle_adm_err("%s: get from qdsp via adm with port id 0x%X failed",
-                                __func__, pid);
-                       return -EFAULT;
-               }
-       } else if (_is_port_open_and_eagle(pid)) {
-               cidx = adm_validate_and_get_port_index(pid);
-               eagle_adm_dbg("%s: adm_dts_eagle_set called with id = 0x%X, size = %u, offset = %i, device = %u, port id = %u, copp index = %u",
-                               __func__, depd->id, depd->size, depd->offset,
-                               depd->device, pid, cidx);
-               ret = adm_dts_eagle_set(pid, _cidx[cidx], depd->id,
-                                       (void *)buf, depd->size);
-               if (ret < 0)
-                       eagle_adm_err("%s: adm_dts_eagle_set failed", __func__);
-               else
-                       eagle_adm_dbg("%s: adm_dts_eagle_set succeeded",
-                               __func__);
-       } else {
-               ret = -EINVAL;
-               eagle_adm_dbg("%s: port id 0x%X not active or not Eagle",
-                        __func__, pid);
-       }
-       return (int)ret;
-}
-
-/**
- * msm_dts_eagle_ioctl() - ioctl handler function
- * @cmd:       cmd to handle.
- * @arg:       argument to the cmd.
- *
- * Handle DTS Eagle ioctl cmds.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg)
-{
-       s32 ret = 0;
-       switch (cmd) {
-       case DTS_EAGLE_IOCTL_GET_CACHE_SIZE: {
-               eagle_ioctl_info("%s: called with control 0x%X (get param cache size)",
-                       __func__, cmd);
-               if (copy_to_user((void *)arg, &_depc_size,
-                                sizeof(_depc_size))) {
-                       eagle_ioctl_err("%s: error writing size", __func__);
-                       return -EFAULT;
-               }
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SET_CACHE_SIZE: {
-               u32 size = 0;
-               eagle_ioctl_info("%s: called with control 0x%X (allocate param cache)",
-                       __func__, cmd);
-               if (copy_from_user((void *)&size, (void *)arg, sizeof(size))) {
-                       eagle_ioctl_err("%s: error copying size (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, &size, sizeof(size));
-                       return -EFAULT;
-               } else if (size > DEPC_MAX_SIZE) {
-                       eagle_ioctl_err("%s: cache size %u not allowed (min 0, max %u)",
-                               __func__, size, DEPC_MAX_SIZE);
-                       return -EINVAL;
-               }
-               if (_depc) {
-                       eagle_ioctl_dbg("%s: previous param cache of size %u freed",
-                               __func__, _depc_size);
-                       _depc_size = 0;
-                       vfree(_depc);
-                       _depc = NULL;
-               }
-               if (size)
-                       _depc = vzalloc(size);
-               else
-                       eagle_ioctl_dbg("%s: %u bytes requested for param cache, nothing allocated",
-                               __func__, size);
-               if (_depc) {
-                       eagle_ioctl_dbg("%s: %u bytes allocated for param cache",
-                               __func__, size);
-                       _depc_size = size;
-               } else {
-                       eagle_ioctl_err("%s: error allocating param cache (vzalloc failed on %u bytes)",
-                               __func__, size);
-                       _depc_size = 0;
-                       return -ENOMEM;
-               }
-               break;
-       }
-       case DTS_EAGLE_IOCTL_GET_PARAM: {
-               struct dts_eagle_param_desc depd;
-               s32 for_pre = 0, get_from_core = 0, err = 0;
-               u32 offset;
-               void *buf, *buf_m = NULL;
-               eagle_ioctl_info("%s: control 0x%X (get param)",
-                       __func__, cmd);
-               if (copy_from_user((void *)&depd, (void *)arg, sizeof(depd))) {
-                       eagle_ioctl_err("%s: error copying dts_eagle_param_desc (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, &depd, sizeof(depd));
-                       return -EFAULT;
-               }
-               if (depd.device & DTS_EAGLE_FLAG_IOCTL_PRE) {
-                       eagle_ioctl_dbg("%s: using for premix", __func__);
-                       for_pre = 1;
-               }
-               if (depd.device & DTS_EAGLE_FLAG_IOCTL_GETFROMCORE) {
-                       eagle_ioctl_dbg("%s: 'get from core' requested",
-                               __func__);
-                       get_from_core = 1;
-                       depd.offset = -1;
-               }
-               depd.device &= DTS_EAGLE_FLAG_IOCTL_MASK;
-               if (depd.offset == -1) {
-                       if (depd.size > 0 && depd.size <= DEPC_MAX_SIZE) {
-                               buf = buf_m = vzalloc(depd.size);
-                       } else {
-                               eagle_ioctl_err("%s: get size %u invalid",
-                                               __func__, depd.size);
-                               return -EINVAL;
-                       }
-                       if (!buf_m) {
-                               eagle_ioctl_err("%s: out of memory", __func__);
-                               return -ENOMEM;
-                       }
-                       if (get_from_core)
-                               ret = core_dts_eagle_get(depd.id, depd.size,
-                                                        buf);
-                       else
-                               ret = msm_dts_eagle_handle_adm(&depd, buf,
-                                                               for_pre, true);
-               } else {
-                       s32 cb = _get_cb_for_dev(depd.device);
-                       if (cb < 0) {
-                               eagle_ioctl_err("%s: no cache for device %u found",
-                                       __func__, depd.device);
-                               return -EINVAL;
-                       }
-                       offset = _c_bl[cb][CBD_OFFSG] + depd.offset;
-                       /* check for integer overflow */
-                       if (offset > (UINT_MAX - depd.size))
-                               err = -EINVAL;
-                       if ((err != 0) ||
-                           ((offset + depd.size) > _depc_size)) {
-                               eagle_ioctl_err("%s: invalid size %u and/or offset %u",
-                                       __func__, depd.size, offset);
-                               return -EINVAL;
-                       }
-                       buf = (void *)&_depc[offset];
-               }
-               if (ret < 0)
-                       eagle_ioctl_err("%s: error %i getting data", __func__,
-                               ret);
-               else if (copy_to_user((void *)(((char *)arg)+sizeof(depd)),
-                                                 buf, depd.size)) {
-                       eagle_ioctl_err("%s: error copying get data", __func__);
-                       ret = -EFAULT;
-               }
-               vfree(buf_m);
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SET_PARAM: {
-               struct dts_eagle_param_desc depd;
-               s32 just_set_cache = 0, for_pre = 0, err = 0;
-               u32 offset;
-               s32 tgt;
-               eagle_ioctl_info("%s: control 0x%X (set param)",
-                       __func__, cmd);
-               if (copy_from_user((void *)&depd, (void *)arg, sizeof(depd))) {
-                       eagle_ioctl_err("%s: error copying dts_eagle_param_desc (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, &depd, sizeof(depd));
-                       return -EFAULT;
-               }
-               if (depd.device & DTS_EAGLE_FLAG_IOCTL_PRE) {
-                       eagle_ioctl_dbg("%s: using for premix", __func__);
-                       for_pre = 1;
-               }
-               if (depd.device & DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE) {
-                       eagle_ioctl_dbg("%s: 'just set cache' requested",
-                               __func__);
-                       just_set_cache = 1;
-               }
-               depd.device &= DTS_EAGLE_FLAG_IOCTL_MASK;
-               tgt = _get_cb_for_dev(depd.device);
-               if (tgt < 0) {
-                       eagle_ioctl_err("%s: no cache for device %u found",
-                               __func__, depd.device);
-                       return -EINVAL;
-               }
-               offset = _c_bl[tgt][CBD_OFFSG] + depd.offset;
-               /* check for integer overflow */
-               if (offset > (UINT_MAX - depd.size))
-                       err = -EINVAL;
-               if ((err != 0) || ((offset + depd.size) > _depc_size)) {
-                       eagle_ioctl_err("%s: invalid size %u and/or offset %u for parameter (target cache block %i with offset %i, global cache is size %u)",
-                               __func__, depd.size, offset, tgt,
-                               _c_bl[tgt][CBD_OFFSG], _depc_size);
-                       return -EINVAL;
-               }
-               if (copy_from_user((void *)&_depc[offset],
-                                  (void *)(((char *)arg)+sizeof(depd)),
-                                       depd.size)) {
-                       eagle_ioctl_err("%s: error copying param to cache (src:%pK, tgt:%pK, size:%u)",
-                               __func__, ((char *)arg)+sizeof(depd),
-                               &_depc[offset], depd.size);
-                       return -EFAULT;
-               }
-               eagle_ioctl_dbg("%s: param info: param = 0x%X, size = %u, offset = %i, device = %u, cache block %i, global offset = %u, first bytes as integer = %i",
-                       __func__, depd.id, depd.size, depd.offset,
-                       depd.device, tgt, offset, *(int *)&_depc[offset]);
-               if (!just_set_cache) {
-                       ret = msm_dts_eagle_handle_adm(&depd, &_depc[offset],
-                                                      for_pre, false);
-               }
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK: {
-               u32 b_[CBD_COUNT+1], *b = &b_[1], cb;
-               eagle_ioctl_info("%s: with control 0x%X (set param cache block)",
-                        __func__, cmd);
-               if (copy_from_user((void *)b_, (void *)arg, sizeof(b_))) {
-                       eagle_ioctl_err("%s: error copying cache block data (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, b_, sizeof(b_));
-                       return -EFAULT;
-               }
-               cb = b_[0];
-               if (cb >= CB_COUNT) {
-                       eagle_ioctl_err("%s: cache block %u out of range (max %u)",
-                               __func__, cb, CB_COUNT-1);
-                       return -EINVAL;
-               }
-               eagle_ioctl_dbg("%s: cache block %i set: devices 0x%X, global offset %i, offsets 1:%u 2:%u 3:%u, cmds/sizes 0:0x%X %u 1:0x%X %u 2:0x%X %u 3:0x%X %u",
-               __func__, cb, _c_bl[cb][CBD_DEV_MASK], _c_bl[cb][CBD_OFFSG],
-               _c_bl[cb][CBD_OFFS1], _c_bl[cb][CBD_OFFS2],
-               _c_bl[cb][CBD_OFFS3], _c_bl[cb][CBD_CMD0], _c_bl[cb][CBD_SZ0],
-               _c_bl[cb][CBD_CMD1], _c_bl[cb][CBD_SZ1], _c_bl[cb][CBD_CMD2],
-               _c_bl[cb][CBD_SZ2], _c_bl[cb][CBD_CMD3], _c_bl[cb][CBD_SZ3]);
-               if ((b[CBD_OFFSG]+b[CBD_OFFS1]+b[CBD_SZ1]) > _depc_size ||
-                       (b[CBD_OFFSG]+b[CBD_OFFS2]+b[CBD_SZ2]) > _depc_size ||
-                       (b[CBD_OFFSG]+b[CBD_OFFS3]+b[CBD_SZ3]) > _depc_size) {
-                       eagle_ioctl_err("%s: cache block bounds out of range",
-                                       __func__);
-                       return -EINVAL;
-               }
-               memcpy(_c_bl[cb], b, sizeof(_c_bl[cb]));
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE: {
-               u32 data[2];
-               eagle_ioctl_dbg("%s: with control 0x%X (set active device)",
-                        __func__, cmd);
-               if (copy_from_user((void *)data, (void *)arg, sizeof(data))) {
-                       eagle_ioctl_err("%s: error copying active device data (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, data, sizeof(data));
-                       return -EFAULT;
-               }
-               if (data[1] != 0) {
-                       _device_primary = data[0];
-                       eagle_ioctl_dbg("%s: primary device %i", __func__,
-                                data[0]);
-               } else {
-                       _device_all = data[0];
-                       eagle_ioctl_dbg("%s: all devices 0x%X", __func__,
-                                data[0]);
-               }
-               break;
-       }
-       case DTS_EAGLE_IOCTL_GET_LICENSE: {
-               u32 target = 0, size = 0;
-               s32 size_only;
-               eagle_ioctl_dbg("%s: with control 0x%X (get license)",
-                        __func__, cmd);
-               if (copy_from_user((void *)&target, (void *)arg,
-                                  sizeof(target))) {
-                       eagle_ioctl_err("%s: error reading license index. (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, &target, sizeof(target));
-                       return -EFAULT;
-               }
-               size_only = target & (1<<31) ? 1 : 0;
-               target &= 0x7FFFFFFF;
-               if (target >= SEC_BLOB_MAX_CNT) {
-                       eagle_ioctl_err("%s: license index %u out of bounds (max index is %i)",
-                                  __func__, target, SEC_BLOB_MAX_CNT);
-                       return -EINVAL;
-               }
-               if (_sec_blob[target] == NULL) {
-                       eagle_ioctl_err("%s: license index %u never initialized",
-                                  __func__, target);
-                       return -EINVAL;
-               }
-               size = ((u32 *)_sec_blob[target])[0];
-               if ((size == 0) || (size > SEC_BLOB_MAX_SIZE)) {
-                       eagle_ioctl_err("%s: license size %u for index %u invalid (min size is 1, max size is %u)",
-                                  __func__, size, target, SEC_BLOB_MAX_SIZE);
-                       return -EINVAL;
-               }
-               if (size_only) {
-                       eagle_ioctl_dbg("%s: reporting size of license data only",
-                                       __func__);
-                       if (copy_to_user((void *)(((char *)arg)+sizeof(target)),
-                                (void *)&size, sizeof(size))) {
-                               eagle_ioctl_err("%s: error copying license size",
-                                               __func__);
-                               return -EFAULT;
-                       }
-               } else if (copy_to_user((void *)(((char *)arg)+sizeof(target)),
-                          (void *)&(((s32 *)_sec_blob[target])[1]), size)) {
-                       eagle_ioctl_err("%s: error copying license data",
-                               __func__);
-                       return -EFAULT;
-               } else
-                       eagle_ioctl_info("%s: license file %u bytes long from license index %u returned to user",
-                                 __func__, size, target);
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SET_LICENSE: {
-               u32 target[2] = {0, 0};
-               eagle_ioctl_dbg("%s: control 0x%X (set license)", __func__,
-                               cmd);
-               if (copy_from_user((void *)target, (void *)arg,
-                                  sizeof(target))) {
-                       eagle_ioctl_err("%s: error reading license index (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, target, sizeof(target));
-                       return -EFAULT;
-               }
-               if (target[0] >= SEC_BLOB_MAX_CNT) {
-                       eagle_ioctl_err("%s: license index %u out of bounds (max index is %u)",
-                                  __func__, target[0], SEC_BLOB_MAX_CNT-1);
-                       return -EINVAL;
-               }
-               if (target[1] == 0) {
-                       eagle_ioctl_dbg("%s: request to free license index %u",
-                                __func__, target[0]);
-                       kfree(_sec_blob[target[0]]);
-                       _sec_blob[target[0]] = NULL;
-                       break;
-               }
-               if ((target[1] == 0) || (target[1] >= SEC_BLOB_MAX_SIZE)) {
-                       eagle_ioctl_err("%s: license size %u for index %u invalid (min size is 1, max size is %u)",
-                               __func__, target[1], target[0],
-                               SEC_BLOB_MAX_SIZE);
-                       return -EINVAL;
-               }
-               if (_sec_blob[target[0]] != NULL) {
-                       if (((u32 *)_sec_blob[target[0]])[1] != target[1]) {
-                               eagle_ioctl_dbg("%s: request new size for already allocated license index %u",
-                                        __func__, target[0]);
-                       }
-                       kfree(_sec_blob[target[0]]);
-                       _sec_blob[target[0]] = NULL;
-               }
-               eagle_ioctl_dbg("%s: allocating %u bytes for license index %u",
-                               __func__, target[1], target[0]);
-               _sec_blob[target[0]] = kzalloc(target[1] + 4, GFP_KERNEL);
-               if (!_sec_blob[target[0]]) {
-                       eagle_ioctl_err("%s: error allocating license index %u (kzalloc failed on %u bytes)",
-                                       __func__, target[0], target[1]);
-                       return -ENOMEM;
-               }
-               ((u32 *)_sec_blob[target[0]])[0] = target[1];
-               if (copy_from_user(
-                               (void *)&(((u32 *)_sec_blob[target[0]])[1]),
-                               (void *)(((char *)arg)+sizeof(target)),
-                               target[1])) {
-                       eagle_ioctl_err("%s: error copying license to index %u, size %u (src:%pK, tgt:%pK, size:%u)",
-                                       __func__, target[0], target[1],
-                                       ((char *)arg)+sizeof(target),
-                                       &(((u32 *)_sec_blob[target[0]])[1]),
-                                       target[1]);
-                       return -EFAULT;
-               } else
-                       eagle_ioctl_info("%s: license file %u bytes long copied to index license index %u",
-                                 __func__, target[1], target[0]);
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SEND_LICENSE: {
-               u32 target = 0;
-               eagle_ioctl_dbg("%s: control 0x%X (send license)", __func__,
-                               cmd);
-               if (copy_from_user((void *)&target, (void *)arg,
-                                  sizeof(target))) {
-                       eagle_ioctl_err("%s: error reading license index (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, &target, sizeof(target));
-                       return -EFAULT;
-               }
-               if (target >= SEC_BLOB_MAX_CNT) {
-                       eagle_ioctl_err("%s: license index %u out of bounds (max index is %i)",
-                                       __func__, target, SEC_BLOB_MAX_CNT-1);
-                       return -EINVAL;
-               }
-               if (!_sec_blob[target] ||
-                   ((u32 *)_sec_blob[target])[0] == 0) {
-                       eagle_ioctl_err("%s: license index %u is invalid",
-                               __func__, target);
-                       return -EINVAL;
-               }
-               if (core_dts_eagle_set(((s32 *)_sec_blob[target])[0],
-                               (char *)&((s32 *)_sec_blob[target])[1]) < 0)
-                       eagle_ioctl_err("%s: core_dts_eagle_set failed with id = %u",
-                               __func__, target);
-               else
-                       eagle_ioctl_info("%s: core_dts_eagle_set succeeded with id = %u",
-                                __func__, target);
-               break;
-       }
-       case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS: {
-               s32 spec = 0;
-               eagle_ioctl_info("%s: control 0x%X (set volume commands)",
-                               __func__, cmd);
-               if (copy_from_user((void *)&spec, (void *)arg,
-                                       sizeof(spec))) {
-                       eagle_ioctl_err("%s: error reading volume command specifier (src:%pK, tgt:%pK, size:%zu)",
-                               __func__, (void *)arg, &spec, sizeof(spec));
-                       return -EFAULT;
-               }
-               if (spec & 0x80000000) {
-                       u32 idx = (spec & 0x0000F000) >> 12;
-                       s32 size = spec & 0x00000FFF;
-                       eagle_ioctl_dbg("%s: setting volume command %i size: %i",
-                               __func__, idx, size);
-                       if (idx >= _vol_cmd_cnt) {
-                               eagle_ioctl_err("%s: volume command index %u out of bounds (only %u allocated)",
-                                       __func__, idx, _vol_cmd_cnt);
-                               return -EINVAL;
-                       }
-                       if (_volume_cmds_alloc2(idx, size) < 0) {
-                               eagle_ioctl_err("%s: error allocating memory for volume controls",
-                                               __func__);
-                               return -ENOMEM;
-                       }
-                       if (copy_from_user((void *)&_vol_cmds_d[idx],
-                                       (void *)(((char *)arg) + sizeof(int)),
-                                       sizeof(struct vol_cmds_d))) {
-                               eagle_ioctl_err("%s: error reading volume command descriptor (src:%pK, tgt:%pK, size:%zu)",
-                                       __func__, ((char *)arg) + sizeof(int),
-                                       &_vol_cmds_d[idx],
-                                       sizeof(struct vol_cmds_d));
-                               return -EFAULT;
-                       }
-                       eagle_ioctl_dbg("%s: setting volume command %i spec (size %zu): %i %i %i %i",
-                                 __func__, idx, sizeof(struct vol_cmds_d),
-                                 _vol_cmds_d[idx].d[0], _vol_cmds_d[idx].d[1],
-                                 _vol_cmds_d[idx].d[2], _vol_cmds_d[idx].d[3]);
-                       if (copy_from_user((void *)_vol_cmds[idx],
-                                       (void *)(((char *)arg) + (sizeof(int) +
-                                       sizeof(struct vol_cmds_d))), size)) {
-                               eagle_ioctl_err("%s: error reading volume command string (src:%pK, tgt:%pK, size:%i)",
-                                       __func__, ((char *)arg) + (sizeof(int) +
-                                       sizeof(struct vol_cmds_d)),
-                                       _vol_cmds[idx], size);
-                               return -EFAULT;
-                       }
-               } else {
-                       eagle_ioctl_dbg("%s: setting volume command size",
-                                       __func__);
-                       if (spec < 0 || spec > VOL_CMD_CNT_MAX) {
-                               eagle_ioctl_err("%s: volume command count %i out of bounds (min 0, max %i)",
-                                       __func__, spec, VOL_CMD_CNT_MAX);
-                               return -EINVAL;
-                       } else if (spec == 0) {
-                               eagle_ioctl_dbg("%s: request to free volume commands",
-                                               __func__);
-                               _volume_cmds_free();
-                               break;
-                       }
-                       eagle_ioctl_dbg("%s: setting volume command size requested = %i",
-                                 __func__, spec);
-                       if (_volume_cmds_alloc1(spec) < 0) {
-                               eagle_ioctl_err("%s: error allocating memory for volume controls",
-                                               __func__);
-                               return -ENOMEM;
-                       }
-               }
-               break;
-       }
-       default: {
-               eagle_ioctl_err("%s: control 0x%X (invalid control)",
-                        __func__, cmd);
-               ret = -EINVAL;
-       }
-       }
-       return (int)ret;
-}
-
-/**
- * msm_dts_eagle_compat_ioctl() - To handle 32bit to 64bit ioctl compatibility
- * @cmd:       cmd to handle.
- * @arg:       argument to the cmd.
- *
- * Handle DTS Eagle ioctl cmds from 32bit userspace.
- *
- * Return: Return failure if any.
- */
-#ifdef CONFIG_COMPAT
-int msm_dts_eagle_compat_ioctl(unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case DTS_EAGLE_IOCTL_GET_CACHE_SIZE32:
-               cmd = DTS_EAGLE_IOCTL_GET_CACHE_SIZE;
-               break;
-       case DTS_EAGLE_IOCTL_SET_CACHE_SIZE32:
-               cmd = DTS_EAGLE_IOCTL_SET_CACHE_SIZE;
-               break;
-       case DTS_EAGLE_IOCTL_GET_PARAM32:
-               cmd = DTS_EAGLE_IOCTL_GET_PARAM;
-               break;
-       case DTS_EAGLE_IOCTL_SET_PARAM32:
-               cmd = DTS_EAGLE_IOCTL_SET_PARAM;
-               break;
-       case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32:
-               cmd = DTS_EAGLE_IOCTL_SET_CACHE_BLOCK;
-               break;
-       case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32:
-               cmd = DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE;
-               break;
-       case DTS_EAGLE_IOCTL_GET_LICENSE32:
-               cmd = DTS_EAGLE_IOCTL_GET_LICENSE;
-               break;
-       case DTS_EAGLE_IOCTL_SET_LICENSE32:
-               cmd = DTS_EAGLE_IOCTL_SET_LICENSE;
-               break;
-       case DTS_EAGLE_IOCTL_SEND_LICENSE32:
-               cmd = DTS_EAGLE_IOCTL_SEND_LICENSE;
-               break;
-       case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32:
-               cmd = DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS;
-               break;
-       default:
-               break;
-       }
-       return msm_dts_eagle_ioctl(cmd, arg);
-}
-#endif
-/**
- * msm_dts_eagle_init_pre() - Initialize DTS premix module
- * @ac:        Initialize premix module in the ASM session.
- *
- * Initialize DTS premix module on provided ASM session
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_init_pre(struct audio_client *ac)
-{
-       return msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
-                                AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-}
-
-/**
- * msm_dts_eagle_deinit_pre() - Deinitialize DTS premix module
- * @ac:        Deinitialize premix module in the ASM session.
- *
- * Deinitialize DTS premix module on provided ASM session
- *
- * Return: Currently does nothing so 0.
- */
-int msm_dts_eagle_deinit_pre(struct audio_client *ac)
-{
-       return 0;
-}
-
-/**
- * msm_dts_eagle_init_post() - Initialize DTS postmix module
- * @port_id:   Port id for the ADM session.
- * @copp_idx:  Copp idx for the ADM session.
- *
- * Initialize DTS postmix module on ADM session
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_init_post(int port_id, int copp_idx)
-{
-       return msm_dts_eagle_enable_adm(port_id, copp_idx, _is_hpx_enabled);
-}
-
-/**
- * msm_dts_eagle_deinit_post() - Deinitialize DTS postmix module
- * @port_id:   Port id for the ADM session.
- * @topology:  Topology in use.
- *
- * Deinitialize DTS postmix module on ADM session
- *
- * Return: Currently does nothing so 0.
- */
-int msm_dts_eagle_deinit_post(int port_id, int topology)
-{
-       return 0;
-}
-
-/**
- * msm_dts_eagle_init_master_module() - Initialize both DTS modules
- * @ac:        Initialize modules in the ASM session.
- *
- * Initialize DTS modules on ASM session
- *
- * Return: Success.
- */
-int msm_dts_eagle_init_master_module(struct audio_client *ac)
-{
-       _set_audioclient(ac);
-       msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
-                                AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-       msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
-                                AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
-       return 0;
-}
-
-/**
- * msm_dts_eagle_deinit_master_module() - Deinitialize both DTS modules
- * @ac:        Deinitialize modules in the ASM session.
- *
- * Deinitialize DTS modules on ASM session
- *
- * Return: Success.
- */
-int msm_dts_eagle_deinit_master_module(struct audio_client *ac)
-{
-       msm_dts_eagle_deinit_pre(ac);
-       msm_dts_eagle_deinit_post(-1, 0);
-       _clear_audioclient();
-       return 0;
-}
-
-/**
- * msm_dts_eagle_is_hpx_on() - Check if HPX effects are On
- *
- * Check if HPX effects are On
- *
- * Return: On/Off.
- */
-int msm_dts_eagle_is_hpx_on(void)
-{
-       return _is_hpx_enabled;
-}
-
-/**
- * msm_dts_eagle_pcm_new() - Create hwdep node
- * @runtime:   snd_soc_pcm_runtime structure.
- *
- * Create hwdep node
- *
- * Return: Success.
- */
-int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime)
-{
-       if (!_ref_cnt++) {
-               _init_cb_descs();
-               _reg_ion_mem();
-       }
-       return 0;
-}
-
-/**
- * msm_dts_eagle_pcm_free() - remove hwdep node
- * @runtime:   snd_soc_pcm_runtime structure.
- *
- * Remove hwdep node
- *
- * Return: void.
- */
-void msm_dts_eagle_pcm_free(struct snd_pcm *pcm)
-{
-       if (!--_ref_cnt)
-               _unreg_ion_mem();
-       vfree(_depc);
-}
-
-MODULE_DESCRIPTION("DTS EAGLE platform driver");
-MODULE_LICENSE("GPL v2");
index 7c35d19..8fc49b2 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2014, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -19,7 +20,6 @@
 #include <sound/control.h>
 #include <sound/q6adm-v2.h>
 #include <sound/asound.h>
-#include <sound/msm-dts-eagle.h>
 #include "msm-dts-srs-tm-config.h"
 #include "msm-pcm-routing-v2.h"
 
index 109e1a2..1003dc8 100644 (file)
@@ -1312,7 +1312,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
                }
 
                size = sizeof(*user) + userarg32.payload_size;
-               user = kmalloc(size, GFP_KERNEL);
+               user = kzalloc(size, GFP_KERNEL);
                if (!user) {
                        dev_err(rtd->dev,
                                "%s: Allocation failed event status size %d\n",
@@ -1333,7 +1333,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
                        err = -EFAULT;
                }
                if (!err) {
-                       user32 = kmalloc(size, GFP_KERNEL);
+                       user32 = kzalloc(size, GFP_KERNEL);
                        if (!user32) {
                                dev_err(rtd->dev,
                                        "%s: Allocation event user status size %d\n",
@@ -1378,7 +1378,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
                }
 
                size = sizeof(*user) + userarg32.payload_size;
-               user = kmalloc(size, GFP_KERNEL);
+               user = kzalloc(size, GFP_KERNEL);
                if (!user) {
                        dev_err(rtd->dev,
                                "%s: Allocation failed event status size %d\n",
@@ -1398,7 +1398,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
                        err = -EFAULT;
                }
                if (!err) {
-                       user32 = kmalloc(size, GFP_KERNEL);
+                       user32 = kzalloc(size, GFP_KERNEL);
                        if (!user32) {
                                dev_err(rtd->dev,
                                        "%s: Allocation event user status size %d\n",
@@ -1813,7 +1813,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 
                size = sizeof(struct snd_lsm_event_status) +
                userarg.payload_size;
-               user = kmalloc(size, GFP_KERNEL);
+               user = kzalloc(size, GFP_KERNEL);
                if (!user) {
                        dev_err(rtd->dev,
                                "%s: Allocation failed event status size %d\n",
@@ -1874,7 +1874,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 
                size = sizeof(struct snd_lsm_event_status_v3) +
                        userarg.payload_size;
-               user = kmalloc(size, GFP_KERNEL);
+               user = kzalloc(size, GFP_KERNEL);
                if (!user) {
                        dev_err(rtd->dev,
                                "%s: Allocation failed event status size %d\n",
index 3263a57..1dc7d72 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 2017 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,8 +16,6 @@
 #include <linux/module.h>
 #include <sound/hwdep.h>
 #include <sound/devdep_params.h>
-#include <sound/msm-dts-eagle.h>
-
 #include "msm-pcm-routing-devdep.h"
 #include "msm-ds2-dap-config.h"
 
@@ -55,23 +53,6 @@ static int msm_pcm_routing_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
        case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER:
                ret = msm_ds2_dap_ioctl(hw, file, cmd, argp);
                break;
-       case DTS_EAGLE_IOCTL_GET_CACHE_SIZE:
-       case DTS_EAGLE_IOCTL_SET_CACHE_SIZE:
-       case DTS_EAGLE_IOCTL_GET_PARAM:
-       case DTS_EAGLE_IOCTL_SET_PARAM:
-       case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK:
-       case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE:
-       case DTS_EAGLE_IOCTL_GET_LICENSE:
-       case DTS_EAGLE_IOCTL_SET_LICENSE:
-       case DTS_EAGLE_IOCTL_SEND_LICENSE:
-       case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS:
-               ret = msm_dts_eagle_ioctl(cmd, arg);
-               if (ret == -EPERM) {
-                       pr_err("%s called with invalid control 0x%X\n",
-                               __func__, cmd);
-                       ret = -EINVAL;
-               }
-               break;
        default:
                pr_err("%s called with invalid control 0x%X\n", __func__, cmd);
                ret = -EINVAL;
@@ -83,7 +64,6 @@ static int msm_pcm_routing_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
 void msm_pcm_routing_hwdep_free(struct snd_pcm *pcm)
 {
        pr_debug("%s\n", __func__);
-       msm_dts_eagle_pcm_free(pcm);
 }
 
 #ifdef CONFIG_COMPAT
@@ -107,23 +87,6 @@ static int msm_pcm_routing_hwdep_compat_ioctl(struct snd_hwdep *hw,
        case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER32:
                ret = msm_ds2_dap_compat_ioctl(hw, file, cmd, argp);
                break;
-       case DTS_EAGLE_IOCTL_GET_CACHE_SIZE32:
-       case DTS_EAGLE_IOCTL_SET_CACHE_SIZE32:
-       case DTS_EAGLE_IOCTL_GET_PARAM32:
-       case DTS_EAGLE_IOCTL_SET_PARAM32:
-       case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32:
-       case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32:
-       case DTS_EAGLE_IOCTL_GET_LICENSE32:
-       case DTS_EAGLE_IOCTL_SET_LICENSE32:
-       case DTS_EAGLE_IOCTL_SEND_LICENSE32:
-       case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32:
-               ret = msm_dts_eagle_compat_ioctl(cmd, arg);
-               if (ret == -EPERM) {
-                       pr_err("%s called with invalid control 0x%X\n",
-                               __func__, cmd);
-                       ret = -EINVAL;
-               }
-               break;
        default:
                pr_err("%s called with invalid control 0x%X\n", __func__, cmd);
                ret = -EINVAL;
@@ -169,6 +132,6 @@ int msm_pcm_routing_hwdep_new(struct snd_soc_pcm_runtime *runtime,
 #ifdef CONFIG_COMPAT
        hwdep->ops.ioctl_compat = msm_pcm_routing_hwdep_compat_ioctl;
 #endif
-       return msm_dts_eagle_pcm_new(runtime);
+       return rc;
 }
 #endif
index f461f36..0f63fd6 100644 (file)
@@ -33,7 +33,6 @@
 #include <sound/pcm_params.h>
 #include <sound/q6core.h>
 #include <sound/audio_cal_utils.h>
-#include <sound/msm-dts-eagle.h>
 #include <sound/audio_effects.h>
 #include <sound/hwdep.h>
 
@@ -208,10 +207,6 @@ static void msm_pcm_routing_cfg_pp(int port_id, int copp_idx, int topology,
                                        __func__, topology, port_id, rc);
                }
                break;
-       case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX:
-               pr_debug("%s: DTS_EAGLE_COPP_TOPOLOGY_ID\n", __func__);
-               msm_dts_eagle_init_post(port_id, copp_idx);
-               break;
        case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE:
                pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__);
                rc = msm_qti_pp_asphere_init(port_id, copp_idx);
@@ -246,10 +241,6 @@ static void msm_pcm_routing_deinit_pp(int port_id, int topology)
                        msm_dolby_dap_deinit(port_id);
                }
                break;
-       case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX:
-               pr_debug("%s: DTS_EAGLE_COPP_TOPOLOGY_ID\n", __func__);
-               msm_dts_eagle_deinit_post(port_id, topology);
-               break;
        case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE:
                pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__);
                msm_qti_pp_asphere_deinit(port_id);
@@ -8124,6 +8115,9 @@ static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = {
        SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
        MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
        msm_routing_put_port_mixer),
+       SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+       MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+       msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = {
@@ -8154,6 +8148,9 @@ static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = {
        SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
        MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
        msm_routing_put_port_mixer),
+       SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+       MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+       msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = {
@@ -9244,6 +9241,9 @@ static const struct snd_kcontrol_new tert_mi2s_rx_port_mixer_controls[] = {
        SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
        MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
        msm_routing_put_port_mixer),
+       SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+       MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+       msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = {
@@ -9265,6 +9265,9 @@ static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = {
        SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
        MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
        msm_routing_put_port_mixer),
+       SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+       MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+       msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new lsm1_mixer_controls[] = {
@@ -13890,6 +13893,7 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"PRI_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
        {"PRI_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
        {"PRI_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+       {"PRI_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
        {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Port Mixer"},
 
        {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -13898,6 +13902,7 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
        {"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
        {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+       {"SEC_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
        {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"},
 
        {"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -13905,6 +13910,7 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"TERT_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
        {"TERT_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
        {"TERT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+       {"TERT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
        {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Port Mixer"},
 
        {"QUAT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -13914,6 +13920,7 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"QUAT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
        {"QUAT_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
        {"QUAT_MI2S_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+       {"QUAT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
        {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Port Mixer"},
 
        /* Backend Enablement */
@@ -14116,6 +14123,7 @@ static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
        bedai->active = 0;
        bedai->sample_rate = 0;
        bedai->channel = 0;
+       bedai->passthr_mode = LEGACY_PCM;
        mutex_unlock(&routing_lock);
 
        return 0;
@@ -14685,8 +14693,6 @@ static int msm_routing_probe(struct snd_soc_platform *platform)
                msm_routing_be_dai_name_table_mixer_controls,
                ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls));
 
-       msm_dts_eagle_add_controls(platform);
-
        snd_soc_add_platform_controls(platform, msm_source_tracking_controls,
                                ARRAY_SIZE(msm_source_tracking_controls));
        snd_soc_add_platform_controls(platform, adm_channel_config_controls,
index f026e82..9f00e1b 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/q6afe-v2.h>
 #include <sound/audio_cal_utils.h>
 #include <sound/asound.h>
-#include <sound/msm-dts-eagle.h>
 #include "msm-dts-srs-tm-config.h"
 #include <sound/adsp_err.h>
 
@@ -262,222 +261,6 @@ static int adm_get_next_available_copp(int port_idx)
        return idx;
 }
 
-int adm_dts_eagle_set(int port_id, int copp_idx, int param_id,
-                     void *data, uint32_t size)
-{
-       struct adm_cmd_set_pp_params_v5 admp;
-       int p_idx, ret = 0, *ob_params;
-
-       pr_debug("DTS_EAGLE_ADM: %s - port id %i, copp idx %i, param id 0x%X size %u\n",
-               __func__, port_id, copp_idx, param_id, size);
-
-       port_id = afe_convert_virtual_to_portid(port_id);
-       p_idx = adm_validate_and_get_port_index(port_id);
-       pr_debug("DTS_EAGLE_ADM: %s - after lookup, port id %i, port idx %i\n",
-               __func__, port_id, p_idx);
-
-       if (p_idx < 0) {
-               pr_err("DTS_EAGLE_ADM: %s: invalid port index 0x%x, port id 0x%x\n",
-                       __func__, p_idx, port_id);
-               return -EINVAL;
-       }
-
-       if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
-               pr_err("DTS_EAGLE_ADM: %s: Invalid copp_idx: %d\n", __func__,
-                       copp_idx);
-               return -EINVAL;
-       }
-
-       ob_params = (int *)this_adm.outband_memmap.kvaddr;
-       if (ob_params == NULL) {
-               pr_err("DTS_EAGLE_ADM: %s - NULL memmap. Non Eagle topology selected?\n",
-                       __func__);
-               ret = -EINVAL;
-               goto fail_cmd;
-       }
-       /* check for integer overflow */
-       if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-               ret = -EINVAL;
-       if ((ret < 0) ||
-           (size + APR_CMD_OB_HDR_SZ > this_adm.outband_memmap.size)) {
-               pr_err("DTS_EAGLE_ADM - %s: ion alloc of size %zu too small for size requested %u\n",
-                       __func__, this_adm.outband_memmap.size,
-                       size + APR_CMD_OB_HDR_SZ);
-               ret = -EINVAL;
-               goto fail_cmd;
-       }
-       *ob_params++ = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
-       *ob_params++ = param_id;
-       *ob_params++ = size;
-       memcpy(ob_params, data, size);
-
-       admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-       admp.hdr.pkt_size = sizeof(admp);
-       admp.hdr.src_svc = APR_SVC_ADM;
-       admp.hdr.src_domain = APR_DOMAIN_APPS;
-       admp.hdr.src_port = port_id;
-       admp.hdr.dest_svc = APR_SVC_ADM;
-       admp.hdr.dest_domain = APR_DOMAIN_ADSP;
-       admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
-       admp.hdr.token = p_idx << 16 | copp_idx;
-       admp.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
-       admp.payload_addr_lsw = lower_32_bits(this_adm.outband_memmap.paddr);
-       admp.payload_addr_msw = msm_audio_populate_upper_32_bits(
-                                               this_adm.outband_memmap.paddr);
-       admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
-                                         ADM_DTS_EAGLE]);
-       admp.payload_size = size + sizeof(struct adm_param_data_v5);
-
-       pr_debug("DTS_EAGLE_ADM: %s - Command was sent now check Q6 - port id = %d, size %d, module id %x, param id %x.\n",
-                       __func__, admp.hdr.dest_port,
-                       admp.payload_size, AUDPROC_MODULE_ID_DTS_HPX_POSTMIX,
-                       param_id);
-       atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
-       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
-       if (ret < 0) {
-               pr_err("DTS_EAGLE_ADM: %s - ADM enable for port %d failed\n",
-                       __func__, port_id);
-               ret = -EINVAL;
-               goto fail_cmd;
-       }
-       ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
-                       atomic_read(&this_adm.copp.stat
-                       [p_idx][copp_idx]) >= 0,
-                       msecs_to_jiffies(TIMEOUT_MS));
-       if (!ret) {
-               pr_err("DTS_EAGLE_ADM: %s - set params timed out port = %d\n",
-                       __func__, port_id);
-               ret = -EINVAL;
-       } else if (atomic_read(&this_adm.copp.stat
-                               [p_idx][copp_idx]) > 0) {
-               pr_err("%s: DSP returned error[%s]\n",
-                               __func__, adsp_err_get_err_str(
-                               atomic_read(&this_adm.copp.stat
-                               [p_idx][copp_idx])));
-               ret = adsp_err_get_lnx_err_code(
-                               atomic_read(&this_adm.copp.stat
-                               [p_idx][copp_idx]));
-       } else {
-               ret = 0;
-       }
-
-fail_cmd:
-       return ret;
-}
-
-int adm_dts_eagle_get(int port_id, int copp_idx, int param_id,
-                     void *data, uint32_t size)
-{
-       struct adm_cmd_get_pp_params_v5 admp;
-       int p_idx, ret = 0, *ob_params;
-       uint32_t orig_size = size;
-       pr_debug("DTS_EAGLE_ADM: %s - port id %i, copp idx %i, param id 0x%X\n",
-                __func__, port_id, copp_idx, param_id);
-
-       port_id = afe_convert_virtual_to_portid(port_id);
-       p_idx = adm_validate_and_get_port_index(port_id);
-       if (p_idx < 0) {
-               pr_err("DTS_EAGLE_ADM: %s - invalid port index %i, port id %i, copp idx %i\n",
-                               __func__, p_idx, port_id, copp_idx);
-               return -EINVAL;
-       }
-
-       if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
-               pr_err("DTS_EAGLE_ADM: %s: Invalid copp_idx: %d\n", __func__,
-                       copp_idx);
-               return -EINVAL;
-       }
-
-       if ((size == 0) || !data) {
-               pr_err("DTS_EAGLE_ADM: %s - invalid size %u or pointer %pK.\n",
-                       __func__, size, data);
-               return -EINVAL;
-       }
-
-       size = (size+3) & 0xFFFFFFFC;
-
-       ob_params = (int *)(this_adm.outband_memmap.kvaddr);
-       if (ob_params == NULL) {
-               pr_err("DTS_EAGLE_ADM: %s - NULL memmap. Non Eagle topology selected?",
-                       __func__);
-               ret = -EINVAL;
-               goto fail_cmd;
-       }
-       /* check for integer overflow */
-       if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-               ret = -EINVAL;
-       if ((ret < 0) ||
-           (size + APR_CMD_OB_HDR_SZ > this_adm.outband_memmap.size)) {
-               pr_err("DTS_EAGLE_ADM - %s: ion alloc of size %zu too small for size requested %u\n",
-                       __func__, this_adm.outband_memmap.size,
-                       size + APR_CMD_OB_HDR_SZ);
-               ret = -EINVAL;
-               goto fail_cmd;
-       }
-       *ob_params++ = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
-       *ob_params++ = param_id;
-       *ob_params++ = size;
-
-       admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-                            APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-       admp.hdr.pkt_size = sizeof(admp);
-       admp.hdr.src_svc = APR_SVC_ADM;
-       admp.hdr.src_domain = APR_DOMAIN_APPS;
-       admp.hdr.src_port = port_id;
-       admp.hdr.dest_svc = APR_SVC_ADM;
-       admp.hdr.dest_domain = APR_DOMAIN_ADSP;
-       admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
-       admp.hdr.token = p_idx << 16 | copp_idx;
-       admp.hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
-       admp.data_payload_addr_lsw =
-                               lower_32_bits(this_adm.outband_memmap.paddr);
-       admp.data_payload_addr_msw =
-                               msm_audio_populate_upper_32_bits(
-                                               this_adm.outband_memmap.paddr);
-       admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
-                                         ADM_DTS_EAGLE]);
-       admp.module_id = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
-       admp.param_id = param_id;
-       admp.param_max_size = size + sizeof(struct adm_param_data_v5);
-       admp.reserved = 0;
-
-       atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
-
-       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
-       if (ret < 0) {
-               pr_err("DTS_EAGLE_ADM: %s - Failed to get EAGLE Params on port %d\n",
-                       __func__, port_id);
-               ret = -EINVAL;
-               goto fail_cmd;
-       }
-       ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
-                       atomic_read(&this_adm.copp.stat
-                       [p_idx][copp_idx]) >= 0,
-                       msecs_to_jiffies(TIMEOUT_MS));
-       if (!ret) {
-               pr_err("DTS_EAGLE_ADM: %s - EAGLE get params timed out port = %d\n",
-                       __func__, port_id);
-               ret = -EINVAL;
-               goto fail_cmd;
-       } else if (atomic_read(&this_adm.copp.stat
-                               [p_idx][copp_idx]) > 0) {
-               pr_err("%s: DSP returned error[%s]\n",
-                               __func__, adsp_err_get_err_str(
-                               atomic_read(&this_adm.copp.stat
-                               [p_idx][copp_idx])));
-               ret = adsp_err_get_lnx_err_code(
-                               atomic_read(&this_adm.copp.stat
-                                       [p_idx][copp_idx]));
-               goto fail_cmd;
-       }
-
-       memcpy(data, ob_params, orig_size);
-       ret = 0;
-fail_cmd:
-       return ret;
-}
-
 int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
                      void *srs_params)
 {
@@ -2338,13 +2121,6 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
                 __func__, port_id, path, rate, channel_mode, perf_mode,
                 topology);
 
-       /* For DTS EAGLE only, force 24 bit */
-       if ((topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) &&
-               (perf_mode == LEGACY_PCM_MODE)) {
-               bit_width = 24;
-               pr_debug("%s: Force open adm in 24-bit for DTS HPX topology 0x%x\n",
-                       __func__, topology);
-       }
        port_id = q6audio_convert_virtual_to_portid(port_id);
        port_idx = adm_validate_and_get_port_index(port_id);
        if (port_idx < 0) {
@@ -2366,8 +2142,7 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
                flags = ADM_ULL_POST_PROCESSING_DEVICE_SESSION;
                if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
                    (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
-                   (topology == SRS_TRUMEDIA_TOPOLOGY_ID) ||
-                   (topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX))
+                   (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
                        topology = DEFAULT_COPP_TOPOLOGY;
        } else if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
                flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
@@ -2378,8 +2153,7 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
                flags = ADM_LOW_LATENCY_DEVICE_SESSION;
                if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
                    (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
-                   (topology == SRS_TRUMEDIA_TOPOLOGY_ID) ||
-                   (topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX))
+                   (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
                        topology = DEFAULT_COPP_TOPOLOGY;
        } else {
                if (path == ADM_PATH_COMPRESSED_RX)
@@ -2449,21 +2223,6 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
                (uint32_t)this_adm.outband_memmap.size);
                }
        }
-               if ((topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) &&
-                   (perf_mode == LEGACY_PCM_MODE)) {
-                       int res = 0;
-                       atomic_set(&this_adm.mem_map_index, ADM_DTS_EAGLE);
-                       msm_dts_ion_memmap(&this_adm.outband_memmap);
-                       res = adm_memory_map_regions(
-                                     &this_adm.outband_memmap.paddr,
-                                     0,
-                                     (uint32_t *)&this_adm.outband_memmap.size,
-                                     1);
-                       if (res < 0)
-                               pr_err("%s: DTS_EAGLE mmap did not work!",
-                                       __func__);
-               }
-               memset(&open, 0, sizeof(struct adm_cmd_device_open_v5));
                open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
                                                   APR_HDR_LEN(APR_HDR_SIZE),
                                                   APR_PKT_VER);
@@ -2809,10 +2568,6 @@ int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
                                        __func__, port_idx, copp_idx);
                                continue;
                        }
-                       if (atomic_read(
-                               &this_adm.copp.topology[port_idx][copp_idx]) ==
-                               ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX)
-                               continue;
                        rtac_add_adm_device(payload_map.port_id[i],
                                            atomic_read(&this_adm.copp.id
                                                        [port_idx][copp_idx]),
@@ -2926,21 +2681,6 @@ int adm_close(int port_id, int perf_mode, int copp_idx)
                        }
                }
 
-               if ((perf_mode == LEGACY_PCM_MODE) &&
-                   (this_adm.outband_memmap.paddr != 0) &&
-                   (atomic_read(
-                       &this_adm.copp.topology[port_idx][copp_idx]) ==
-                       ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX)) {
-                       atomic_set(&this_adm.mem_map_index, ADM_DTS_EAGLE);
-                       ret = adm_memory_unmap_regions();
-                       if (ret < 0) {
-                               pr_err("%s: adm mem unmmap err %d",
-                                       __func__, ret);
-                       } else {
-                               atomic_set(&this_adm.mem_map_handles
-                                          [ADM_DTS_EAGLE], 0);
-                       }
-               }
 
                if ((afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) &&
                    this_adm.sourceTrackingData.memmap.paddr) {
@@ -3412,10 +3152,6 @@ static int adm_init_cal_data(void)
                {NULL, NULL, NULL, NULL, NULL, NULL} },
                {NULL, NULL, cal_utils_match_buf_num} },
 
-               {{DTS_EAGLE_CAL_TYPE,
-               {NULL, NULL, NULL, NULL, NULL, NULL} },
-               {NULL, NULL, cal_utils_match_buf_num} },
-
                {{SRS_TRUMEDIA_CAL_TYPE,
                {NULL, NULL, NULL, NULL, NULL, NULL} },
                {NULL, NULL, cal_utils_match_buf_num} },
index a9241cf..0cf386a 100644 (file)
@@ -38,8 +38,8 @@
 #include <sound/q6asm-v2.h>
 #include <sound/q6audio-v2.h>
 #include <sound/audio_cal_utils.h>
-#include <sound/msm-dts-eagle.h>
 #include <sound/adsp_err.h>
+#include <sound/compress_params.h>
 
 #define TRUE        0x01
 #define FALSE       0x00
@@ -1031,12 +1031,14 @@ void q6asm_audio_client_free(struct audio_client *ac)
        }
 
        rtac_set_asm_handle(ac->session, NULL);
-       apr_deregister(ac->apr2);
-       apr_deregister(ac->apr);
-       q6asm_mmap_apr_dereg();
-       ac->apr2 = NULL;
-       ac->apr = NULL;
-       ac->mmap_apr = NULL;
+       if (!atomic_read(&ac->reset)) {
+               apr_deregister(ac->apr2);
+               apr_deregister(ac->apr);
+               q6asm_mmap_apr_dereg();
+               ac->apr2 = NULL;
+               ac->apr = NULL;
+               ac->mmap_apr = NULL;
+       }
        q6asm_session_free(ac);
 
        pr_debug("%s: APR De-Register\n", __func__);
@@ -1507,7 +1509,6 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
                        }
                        pr_debug("%s: Clearing custom topology\n", __func__);
                }
-               this_mmap.apr = NULL;
 
                cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
                common_client.mmap_apr = NULL;
@@ -1708,8 +1709,10 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
        if (data->opcode == RESET_EVENTS) {
                mutex_lock(&ac->cmd_lock);
                atomic_set(&ac->reset, 1);
-               if (ac->apr == NULL)
+               if (ac->apr == NULL) {
                        ac->apr = ac->apr2;
+                       ac->apr2 = NULL;
+               }
                pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
                        __func__,
                        data->reset_event, data->reset_proc, ac->apr);
@@ -2425,9 +2428,6 @@ static int __q6asm_open_read(struct audio_client *ac,
        open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
 
        open.preprocopo_id = q6asm_get_asm_topology_cal();
-       if ((open.preprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-           (open.preprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS))
-               open.preprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
        open.bits_per_sample = bits_per_sample;
        open.mode_flags = 0x0;
 
@@ -2712,16 +2712,9 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
        open.bits_per_sample = bits_per_sample;
 
        open.postprocopo_id = q6asm_get_asm_topology_cal();
-       if ((ac->perf_mode != LEGACY_PCM_MODE) &&
-           ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-            (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS)))
+       if (ac->perf_mode != LEGACY_PCM_MODE)
                open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
 
-       /* For DTS EAGLE only, force 24 bit */
-       if ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-            (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS))
-               open.bits_per_sample = 24;
-
        pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
                 ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
 
@@ -2948,10 +2941,6 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
        ac->topology = open.postprocopo_id;
        ac->app_type = q6asm_get_asm_app_type_cal();
 
-       /* For DTS EAGLE only, force 24 bit */
-       if ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-            (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER))
-               open.bits_per_sample = 24;
 
        switch (wr_format) {
        case FORMAT_LINEAR_PCM:
@@ -6756,233 +6745,6 @@ fail_cmd:
        return rc;
 }
 
-int q6asm_dts_eagle_set(struct audio_client *ac, int param_id, uint32_t size,
-                       void *data, struct param_outband *po, int m_id)
-{
-       int rc = 0, *ob_params = NULL;
-       uint32_t sz = sizeof(struct asm_dts_eagle_param) + (po ? 0 : size);
-       struct asm_dts_eagle_param *ad;
-
-       if (!ac || ac->apr == NULL || (size == 0) || !data) {
-               pr_err("DTS_EAGLE_ASM - %s: APR handle NULL, invalid size %u or pointer %pK.\n",
-                       __func__, size, data);
-               return -EINVAL;
-       }
-
-       ad = kzalloc(sz, GFP_KERNEL);
-       if (!ad) {
-               pr_err("DTS_EAGLE_ASM - %s: error allocating mem of size %u\n",
-                       __func__, sz);
-               return -ENOMEM;
-       }
-       pr_debug("DTS_EAGLE_ASM - %s: ac %pK param_id 0x%x size %u data %pK m_id 0x%x\n",
-               __func__, ac, param_id, size, data, m_id);
-       q6asm_add_hdr_async(ac, &ad->hdr, sz, 1);
-       ad->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
-       ad->param.data_payload_addr_lsw = 0;
-       ad->param.data_payload_addr_msw = 0;
-
-       ad->param.mem_map_handle = 0;
-       ad->param.data_payload_size = size +
-                                       sizeof(struct asm_stream_param_data_v2);
-       ad->data.module_id = m_id;
-       ad->data.param_id = param_id;
-       ad->data.param_size = size;
-       ad->data.reserved = 0;
-       atomic_set(&ac->cmd_state_pp, -1);
-
-       if (po) {
-               struct list_head *ptr, *next;
-               struct asm_buffer_node *node;
-               pr_debug("DTS_EAGLE_ASM - %s: using out of band memory (virtual %pK, physical %lu)\n",
-                       __func__, po->kvaddr, (long)po->paddr);
-               ad->param.data_payload_addr_lsw = lower_32_bits(po->paddr);
-               ad->param.data_payload_addr_msw =
-                               msm_audio_populate_upper_32_bits(po->paddr);
-               list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
-                       node = list_entry(ptr, struct asm_buffer_node, list);
-                       if (node->buf_phys_addr == po->paddr) {
-                               ad->param.mem_map_handle = node->mmap_hdl;
-                               break;
-                       }
-               }
-               if (ad->param.mem_map_handle == 0) {
-                       pr_err("DTS_EAGLE_ASM - %s: mem map handle not found\n",
-                               __func__);
-                       rc = -EINVAL;
-                       goto fail_cmd;
-               }
-               /* check for integer overflow */
-               if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-                       rc = -EINVAL;
-               if ((rc < 0) || (size + APR_CMD_OB_HDR_SZ > po->size)) {
-                       pr_err("DTS_EAGLE_ASM - %s: ion alloc of size %zu too small for size requested %u\n",
-                               __func__, po->size, size + APR_CMD_OB_HDR_SZ);
-                       rc = -EINVAL;
-                       goto fail_cmd;
-               }
-               ob_params = (int *)po->kvaddr;
-               *ob_params++ = m_id;
-               *ob_params++ = param_id;
-               *ob_params++ = size;
-               memcpy(ob_params, data, size);
-       } else {
-               pr_debug("DTS_EAGLE_ASM - %s: using in band\n", __func__);
-               memcpy(((char *)ad) + sizeof(struct asm_dts_eagle_param),
-                       data, size);
-       }
-       rc = apr_send_pkt(ac->apr, (uint32_t *)ad);
-       if (rc < 0) {
-               pr_err("DTS_EAGLE_ASM - %s: set-params send failed paramid[0x%x]\n",
-                       __func__, ad->data.param_id);
-               rc = -EINVAL;
-               goto fail_cmd;
-       }
-
-       rc = wait_event_timeout(ac->cmd_wait,
-                       (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
-       if (!rc) {
-               pr_err("DTS_EAGLE_ASM - %s: timeout, set-params paramid[0x%x]\n",
-                       __func__, ad->data.param_id);
-               rc = -ETIMEDOUT;
-               goto fail_cmd;
-       }
-
-       if (atomic_read(&ac->cmd_state_pp) > 0) {
-               pr_err("%s: DSP returned error[%s]\n",
-                               __func__, adsp_err_get_err_str(
-                               atomic_read(&ac->cmd_state_pp)));
-               rc = adsp_err_get_lnx_err_code(
-                               atomic_read(&ac->cmd_state_pp));
-               goto fail_cmd;
-       }
-       rc = 0;
-fail_cmd:
-       kfree(ad);
-       return rc;
-}
-
-int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size,
-                       void *data, struct param_outband *po, int m_id)
-{
-       struct asm_dts_eagle_param_get *ad;
-       int rc = 0, *ob_params = NULL;
-       uint32_t sz = sizeof(struct asm_dts_eagle_param) + APR_CMD_GET_HDR_SZ +
-                (po ? 0 : size);
-
-       if (!ac || ac->apr == NULL || (size == 0) || !data) {
-               pr_err("DTS_EAGLE_ASM - %s: APR handle NULL, invalid size %u or pointer %pK\n",
-                       __func__, size, data);
-               return -EINVAL;
-       }
-       ad = kzalloc(sz, GFP_KERNEL);
-       if (!ad) {
-               pr_err("DTS_EAGLE_ASM - %s: error allocating memory of size %u\n",
-                       __func__, sz);
-               return -ENOMEM;
-       }
-       pr_debug("DTS_EAGLE_ASM - %s: ac %pK param_id 0x%x size %u data %pK m_id 0x%x\n",
-               __func__, ac, param_id, size, data, m_id);
-       q6asm_add_hdr(ac, &ad->hdr, sz, TRUE);
-       ad->hdr.opcode = ASM_STREAM_CMD_GET_PP_PARAMS_V2;
-       ad->param.data_payload_addr_lsw = 0;
-       ad->param.data_payload_addr_msw = 0;
-       ad->param.mem_map_handle = 0;
-       ad->param.module_id = m_id;
-       ad->param.param_id = param_id;
-       ad->param.param_max_size = size + APR_CMD_GET_HDR_SZ;
-       ad->param.reserved = 0;
-       atomic_set(&ac->cmd_state, -1);
-
-       generic_get_data = kzalloc(size + sizeof(struct generic_get_data_),
-                                  GFP_KERNEL);
-       if (!generic_get_data) {
-               pr_err("DTS_EAGLE_ASM - %s: error allocating mem of size %u\n",
-                       __func__, size);
-               rc = -ENOMEM;
-               goto fail_cmd;
-       }
-
-       if (po) {
-               struct list_head *ptr, *next;
-               struct asm_buffer_node *node;
-               pr_debug("DTS_EAGLE_ASM - %s: using out of band memory (virtual %pK, physical %lu)\n",
-                        __func__, po->kvaddr, (long)po->paddr);
-               ad->param.data_payload_addr_lsw = lower_32_bits(po->paddr);
-               ad->param.data_payload_addr_msw =
-                               msm_audio_populate_upper_32_bits(po->paddr);
-               list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
-                       node = list_entry(ptr, struct asm_buffer_node, list);
-                       if (node->buf_phys_addr == po->paddr) {
-                               ad->param.mem_map_handle = node->mmap_hdl;
-                               break;
-                       }
-               }
-               if (ad->param.mem_map_handle == 0) {
-                       pr_err("DTS_EAGLE_ASM - %s: mem map handle not found\n",
-                               __func__);
-                       rc = -EINVAL;
-                       goto fail_cmd;
-               }
-               /* check for integer overflow */
-               if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-                       rc = -EINVAL;
-               if ((rc < 0) || (size + APR_CMD_OB_HDR_SZ > po->size)) {
-                       pr_err("DTS_EAGLE_ASM - %s: ion alloc of size %zu too small for size requested %u\n",
-                               __func__, po->size, size + APR_CMD_OB_HDR_SZ);
-                       rc = -EINVAL;
-                       goto fail_cmd;
-               }
-               ob_params = (int *)po->kvaddr;
-               *ob_params++ = m_id;
-               *ob_params++ = param_id;
-               *ob_params++ = size;
-               generic_get_data->is_inband = 0;
-       } else {
-               pr_debug("DTS_EAGLE_ASM - %s: using in band\n", __func__);
-               generic_get_data->is_inband = 1;
-       }
-
-       rc = apr_send_pkt(ac->apr, (uint32_t *)ad);
-       if (rc < 0) {
-               pr_err("DTS_EAGLE_ASM - %s: Commmand 0x%x failed\n", __func__,
-                       ad->hdr.opcode);
-               goto fail_cmd;
-       }
-
-       rc = wait_event_timeout(ac->cmd_wait,
-                       (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
-       if (!rc) {
-               pr_err("DTS_EAGLE_ASM - %s: timeout in get\n",
-                       __func__);
-               rc = -ETIMEDOUT;
-               goto fail_cmd;
-       }
-
-       if (atomic_read(&ac->cmd_state) > 0) {
-               pr_err("%s: DSP returned error[%s]\n",
-                               __func__, adsp_err_get_err_str(
-                               atomic_read(&ac->cmd_state)));
-               rc = adsp_err_get_lnx_err_code(
-                               atomic_read(&ac->cmd_state));
-               goto fail_cmd;
-       }
-
-       if (generic_get_data->valid) {
-               rc = 0;
-               memcpy(data, po ? ob_params : generic_get_data->ints, size);
-       } else {
-               rc = -EINVAL;
-               pr_err("DTS_EAGLE_ASM - %s: EAGLE get params problem getting data - check callback error value\n",
-                       __func__);
-       }
-fail_cmd:
-       kfree(ad);
-       kfree(generic_get_data);
-       generic_get_data = NULL;
-       return rc;
-}
-
 static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
 {
        struct asm_volume_ctrl_master_gain vol;
index 5399a10..4340d31 100644 (file)
@@ -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
@@ -169,7 +169,7 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
                        generic_get_data->valid = 1;
                        generic_get_data->size_in_ints =
                                data->payload_size/sizeof(int);
-                       pr_debug("DTS_EAGLE_CORE callback size = %i\n",
+                       pr_debug("callback size = %i\n",
                                 data->payload_size);
                        memcpy(generic_get_data->ints, data->payload,
                                data->payload_size);
@@ -353,119 +353,6 @@ fail_cmd:
        return ret;
 }
 
-int core_dts_eagle_set(int size, char *data)
-{
-       struct adsp_dts_eagle *payload = NULL;
-       int rc = 0, size_aligned4byte;
-
-       pr_debug("DTS_EAGLE_CORE - %s\n", __func__);
-       if (size <= 0 || !data) {
-               pr_err("DTS_EAGLE_CORE - %s: invalid size %i or pointer %pK.\n",
-                       __func__, size, data);
-               return -EINVAL;
-       }
-
-       size_aligned4byte = (size+3) & 0xFFFFFFFC;
-       mutex_lock(&(q6core_lcl.cmd_lock));
-       ocm_core_open();
-       if (q6core_lcl.core_handle_q) {
-               payload = kzalloc(sizeof(struct adsp_dts_eagle) +
-                                 size_aligned4byte, GFP_KERNEL);
-               if (!payload) {
-                       rc = -ENOMEM;
-                       goto exit;
-               }
-               payload->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
-                                               APR_HDR_LEN(APR_HDR_SIZE),
-                                               APR_PKT_VER);
-               payload->hdr.pkt_size = sizeof(struct adsp_dts_eagle) +
-                                              size_aligned4byte;
-               payload->hdr.src_port = 0;
-               payload->hdr.dest_port = 0;
-               payload->hdr.token = 0;
-               payload->hdr.opcode = ADSP_CMD_SET_DTS_EAGLE_DATA_ID;
-               payload->id = DTS_EAGLE_LICENSE_ID;
-               payload->overwrite = 1;
-               payload->size = size;
-               memcpy(payload->data, data, size);
-               rc = apr_send_pkt(q6core_lcl.core_handle_q,
-                               (uint32_t *)payload);
-               if (rc < 0) {
-                       pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
-                               __func__, payload->hdr.opcode, rc);
-               }
-               kfree(payload);
-       }
-
-exit:
-       mutex_unlock(&(q6core_lcl.cmd_lock));
-       return rc;
-}
-
-int core_dts_eagle_get(int id, int size, char *data)
-{
-       struct apr_hdr ah;
-       int rc = 0;
-
-       pr_debug("DTS_EAGLE_CORE - %s\n", __func__);
-       if (size <= 0 || !data) {
-               pr_err("DTS_EAGLE_CORE - %s: invalid size %i or pointer %pK.\n",
-                       __func__, size, data);
-               return -EINVAL;
-       }
-       mutex_lock(&(q6core_lcl.cmd_lock));
-       ocm_core_open();
-       if (q6core_lcl.core_handle_q) {
-               ah.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
-                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-               ah.pkt_size = sizeof(struct apr_hdr);
-               ah.src_port = 0;
-               ah.dest_port = 0;
-               ah.token = 0;
-               ah.opcode = id;
-
-               q6core_lcl.bus_bw_resp_received = 0;
-               generic_get_data = kzalloc(sizeof(struct generic_get_data_)
-                                          + size, GFP_KERNEL);
-               if (!generic_get_data) {
-                       rc = -ENOMEM;
-                       goto exit;
-               }
-
-               rc = apr_send_pkt(q6core_lcl.core_handle_q,
-                               (uint32_t *)&ah);
-               if (rc < 0) {
-                       pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
-                               __func__, ah.opcode, rc);
-                       goto exit;
-               }
-
-               rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
-                               (q6core_lcl.bus_bw_resp_received == 1),
-                               msecs_to_jiffies(TIMEOUT_MS));
-               if (!rc) {
-                       pr_err("DTS_EAGLE_CORE - %s: EAGLE get params timed out\n",
-                               __func__);
-                       rc = -EINVAL;
-                       goto exit;
-               }
-               if (generic_get_data->valid) {
-                       rc = 0;
-                       memcpy(data, generic_get_data->ints, size);
-               } else {
-                       rc = -EINVAL;
-                       pr_err("DTS_EAGLE_CORE - %s: EAGLE get params problem getting data - check callback error value\n",
-                               __func__);
-               }
-       }
-
-exit:
-       kfree(generic_get_data);
-       generic_get_data = NULL;
-       mutex_unlock(&(q6core_lcl.cmd_lock));
-       return rc;
-}
-
 uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
 {
        struct adsp_dolby_manufacturer_id payload;
@@ -511,21 +398,23 @@ bool q6core_is_adsp_ready(void)
 
        mutex_lock(&(q6core_lcl.cmd_lock));
        ocm_core_open();
-       q6core_lcl.bus_bw_resp_received = 0;
-       rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
-       if (rc < 0) {
-               pr_err("%s: Get ADSP state APR packet send event %d\n",
-                       __func__, rc);
-               goto bail;
-       }
+       if (q6core_lcl.core_handle_q) {
+               q6core_lcl.bus_bw_resp_received = 0;
+               rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+               if (rc < 0) {
+                       pr_err("%s: Get ADSP state APR packet send event %d\n",
+                               __func__, rc);
+                       goto bail;
+               }
 
-       rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
-                               (q6core_lcl.bus_bw_resp_received == 1),
-                               msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
-       if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
-               /* ensure to read updated param by callback thread */
-               rmb();
-               ret = !!q6core_lcl.param;
+               rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+                                       (q6core_lcl.bus_bw_resp_received == 1),
+                                       msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+               if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+                       /* ensure to read updated param by callback thread */
+                       rmb();
+                       ret = !!q6core_lcl.param;
+               }
        }
 bail:
        pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
index 0d9f48e..bc7adb8 100644 (file)
@@ -1433,7 +1433,7 @@ int main(int argc, char *argv[])
        openlog("KVP", 0, LOG_USER);
        syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
 
-       kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR);
+       kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
 
        if (kvp_fd < 0) {
                syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
index 46dbc0a..49001fa 100644 (file)
@@ -868,7 +868,8 @@ kvm_deassign_ioeventfd_idx(struct kvm *kvm, enum kvm_bus bus_idx,
                        continue;
 
                kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
-               kvm->buses[bus_idx]->ioeventfd_count--;
+               if (kvm->buses[bus_idx])
+                       kvm->buses[bus_idx]->ioeventfd_count--;
                ioeventfd_release(p);
                ret = 0;
                break;
index 336ed26..cb092bd 100644 (file)
@@ -654,8 +654,11 @@ static void kvm_destroy_vm(struct kvm *kvm)
        list_del(&kvm->vm_list);
        spin_unlock(&kvm_lock);
        kvm_free_irq_routing(kvm);
-       for (i = 0; i < KVM_NR_BUSES; i++)
-               kvm_io_bus_destroy(kvm->buses[i]);
+       for (i = 0; i < KVM_NR_BUSES; i++) {
+               if (kvm->buses[i])
+                       kvm_io_bus_destroy(kvm->buses[i]);
+               kvm->buses[i] = NULL;
+       }
        kvm_coalesced_mmio_free(kvm);
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
        mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
@@ -3271,6 +3274,8 @@ int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
        };
 
        bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
+       if (!bus)
+               return -ENOMEM;
        r = __kvm_io_bus_write(vcpu, bus, &range, val);
        return r < 0 ? r : 0;
 }
@@ -3288,6 +3293,8 @@ int kvm_io_bus_write_cookie(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx,
        };
 
        bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
+       if (!bus)
+               return -ENOMEM;
 
        /* First try the device referenced by cookie. */
        if ((cookie >= 0) && (cookie < bus->dev_count) &&
@@ -3338,6 +3345,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
        };
 
        bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
+       if (!bus)
+               return -ENOMEM;
        r = __kvm_io_bus_read(vcpu, bus, &range, val);
        return r < 0 ? r : 0;
 }
@@ -3350,6 +3359,9 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
        struct kvm_io_bus *new_bus, *bus;
 
        bus = kvm->buses[bus_idx];
+       if (!bus)
+               return -ENOMEM;
+
        /* exclude ioeventfd which is limited by maximum fd */
        if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
                return -ENOSPC;
@@ -3369,37 +3381,41 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 }
 
 /* Caller must hold slots_lock. */
-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
-                             struct kvm_io_device *dev)
+void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+                              struct kvm_io_device *dev)
 {
-       int i, r;
+       int i;
        struct kvm_io_bus *new_bus, *bus;
 
        bus = kvm->buses[bus_idx];
-       r = -ENOENT;
+       if (!bus)
+               return;
+
        for (i = 0; i < bus->dev_count; i++)
                if (bus->range[i].dev == dev) {
-                       r = 0;
                        break;
                }
 
-       if (r)
-               return r;
+       if (i == bus->dev_count)
+               return;
 
        new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count - 1) *
                          sizeof(struct kvm_io_range)), GFP_KERNEL);
-       if (!new_bus)
-               return -ENOMEM;
+       if (!new_bus)  {
+               pr_err("kvm: failed to shrink bus, removing it completely\n");
+               goto broken;
+       }
 
        memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
        new_bus->dev_count--;
        memcpy(new_bus->range + i, bus->range + i + 1,
               (new_bus->dev_count - i) * sizeof(struct kvm_io_range));
 
+broken:
        rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
        synchronize_srcu_expedited(&kvm->srcu);
        kfree(bus);
-       return r;
+       return;
 }
 
 static struct notifier_block kvm_cpu_notifier = {